Attached are two patches which constitute part of the core developments for protocol-independent handling of IP addresses in squid3.

The patches apply to lib/ and include/ respectively, and do the following:

    - Rollback previous alterations to DNS library code in rfc1035.c
      and return it to the pure IPv4 protocol DNS lookups as defined
      by RFC1035.

    - Fix 0-day bug where base64 code does not provide dependencies
      for utils.h properly.

    - defines new protocol-independant class IPAddress for IP storage
      and handling.


class IPAddress provides:

    - protocol independent storage of in_addr, in6_addr, sockaddr_in,
      and sockaddr_in6.

    - functionality to convert between any of the contained IP formats.
      Either the binary struct or string representations.

    - defines a macro MAX_IPSTRLEN to indicate the length of buffers
      needed to hold string representations of any address string
      produced.

    - functionality to explicitly check the compatible protocol needed
      can be retrieved. Useful for high-level protocols such as WCCP,
      ARP and ICMP which are transport-specific to determine if the
      IPAddress can be one suitable for that protocol.


    The class is built from basic data types and contains no dynamic
    memory operations outside its own allocated block and references
    no pointers. Meaning it can be safely used as a basic data type in
    its own right. With the added abilities of data conversion through
    assignments from any of the above mentioned storage types.

    The storage of sockaddr_* information implies that both port and
    address details are stored, and can be set or retrieved
    independently from any IPAdress which contains them.

    Functionality is provided to convert from hostent structures, but at
    present IPAddress can only hold a single IP. This means the
    conversion will ONLY save the first entry in the hostent list of
    IPA's. Where an non-first entry of the hostent must be stored it
    needs to be explicitly de-referenced and cast from its native char**
    stored format inside hostent to the appropriate in_addr or in6_addr
    type which can then can be passed to the IPAddress object for
    conversion.


Amos Jeffries
Patch file generated Sat Apr  7 15:24:21 NZST 2007 from
CVS branch squid3-ipv6
CVS base branch HEAD
CVS repository: [EMAIL PROTECTED]:/cvsroot/squid
CVS module: squid3/include

cvs -q rdiff -u -kk -r Z-squid3-ipv6_merge_HEAD -r squid3-ipv6 squid3/include
Index: squid3/include/IPAddress.h
diff -u /dev/null squid3/include/IPAddress.h:1.1.2.8
--- /dev/null		Thu Jan  1 01:00:00 1970
+++ squid3/include/IPAddress.h	Thu Apr  5 02:47:56 2007
@@ -0,0 +1,230 @@
+/*
+ * $Id$
+ */
+#ifndef _INC_IPADDRESS_H
+#define _INC_IPADDRESS_H
+
+#include "autoconf.h"
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <iostream>
+#include <netdb.h>
+
+
+/// Specify the type of Address being or to be handled.
+enum IPAddressType {
+        None     =0, ///< Nothing Special. Equates to default if used as a parameter.
+        SockAddr =1, ///< Full SocketAddr Details Stored. Port and Address can be used together or seperately.
+        IPv4     =2, ///< Pure IPv4 address stored (conversion up must be done explicitly)
+        IPv6     =4, ///< Pure IPv6 address Stored (no conversion to IPv4 possible)
+        IPv64    =6  ///< Dual-Address stored (can return either IPv6 OR IPv4)
+};
+
+/// Length of buffer that needs to be allocated to old a null-terminated IP-string
+// Yuck. But there are still structures that need it to be an 'integer constant'.
+#define MAX_IPSTRLEN  75
+
+/**
+ * Holds and manipulates IPv4, IPv6, and Socket Addresses.
+ */
+class IPAddress
+{
+public:
+  /** @name Constructors and Destructor */
+  /[EMAIL PROTECTED]/
+    // default constructor.
+    IPAddress();
+    IPAddress(const IPAddress &);
+    IPAddress(const struct in_addr &);
+    IPAddress(const struct sockaddr_in &);
+#ifdef USE_IPV6
+    IPAddress(const struct in6_addr &);
+    IPAddress(const struct sockaddr_in6 &);
+#endif
+    IPAddress(const hostent *);
+    IPAddress(const char*);
+    /// Default destructor.
+    ~IPAddress();
+    /[EMAIL PROTECTED]/
+
+    /** @name Assignment Operators */
+    /[EMAIL PROTECTED]/
+    IPAddress& operator =(const IPAddress &s);
+    IPAddress& operator =(struct sockaddr_in const &s);
+    IPAddress& operator =(struct in_addr const &s);
+#ifdef USE_IPV6
+    IPAddress& operator =(struct in6_addr const &s);
+    IPAddress& operator =(struct sockaddr_in6 const &s);
+#endif
+    bool operator =(const struct hostent *s);
+    bool operator =(const char *s);
+    /[EMAIL PROTECTED]/
+
+    /** @name Boolean Operators */
+    /[EMAIL PROTECTED]/
+    bool operator ==(IPAddress const &s) const;
+    bool operator >=(IPAddress const &rhs) const;
+    bool operator <=(IPAddress const &rhs) const;
+
+public:
+  /* methods */
+
+            /** Test whether content can be used as an IPv4 address
+             *  \retval true  if content was received as an IPv4 address
+             *  \retval true  if content was received as an IPv4-Mapped address
+             *  \retval false if content was received as a non-mapped IPv6 native address.
+             */
+    inline bool IsIPv4() const { return (m_Type & IPv4); };
+
+            /** Test whether content can be used as an IPv6 address.
+             *  \retval true  if --enable-ipv6 has been compiled.
+             *  \retval false if --disable-ipv6 has been compiled.
+             *  \retval false if --with-ipv6-split-stack has been compiled AND content is IPv4-mapped.
+             */
+    inline bool IsIPv6() const {
+            return (m_Type & IPv6)
+#ifdef USE_IPV6_SPLITSTACK
+                    && !(m_Type & IPv4)
+#endif
+            ;
+        };
+
+            /** Test whether content can be used as a Socket address.
+             *  \retval true  if address AND port are both set
+             *  \retval true  if content was received as a Socket address
+             *  \retval false if port in unset (zero)
+             */
+    inline bool IsSockAddr() const { return (m_Type & SockAddr); };
+
+            /** Content-neutral test for whether the specific IP case ANY_ADDR is stored.
+             *  This is the default content of a new undefined IPAddress object.
+             *  \retval true IPv4 0.0.0.0
+             *  \retval true IPv6 ::
+             *  \retval false anything else.
+             */
+    bool IsAnyAddr() const;
+            /** Content-neutral test for whether the specific IP case NO_ADDR is stored.
+             *  \retval true IPv4 255.255.255.255
+             *  \retval true IPv6 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
+             *  \retval false anything else.
+             */
+    bool IsNoAddr() const;
+    /[EMAIL PROTECTED]/
+
+           /** Retrieve the Port if stored.
+            *  \retval 0 Port is unset or an error occured.
+            *  \retval n Port associated with this address in host native -endian.
+            */
+    u_short GetPort() const;
+           /** Set the Port value for an address.
+            *  Replaces any previously existing Port value.
+            *  \param port Port being assigned in host native -endian.
+            *  \retval 0 Port is unset or an error occured.
+            *  \retval n Port associated with this address in host native -endian.
+            */
+    u_short SetPort(u_short port);
+
+           /// Set object to contain the specific IP case ANY_ADDR (format-neutral).
+           /// see IsAnyAddr() for more detail.
+    void SetAnyAddr();
+
+           /// Set object to contain the specific IP case NO_ADDR (format-neutral).
+           /// see \link IsNoAddr() for more detail.
+    void SetNoAddr();
+
+           /// Fast reset of the stored content to what would be after default constructor.
+    void SetEmpty();
+
+           /** Apply a mask to the stored address.
+            *  \param mask Netmask format to be bit-mask-AND'd over the stored address.
+            */
+    const int ApplyMask(const IPAddress &mask);
+
+           /** Apply a mask to the stored address.
+            *  CIDR will be converted appropriate to map the stored content.
+            *  \param cidr   CIDR Mask being applied. As an integer in host format.
+            *  \param mtype  Type of CIDR mask being applied (IPv4,IPv6, or None for default)
+            */
+    bool ApplyMask(const unsigned int cidr, IPAddressType mtype = None);
+
+
+           /** Return the ASCII equivalent of the address
+            *  Semantically equivalent to the IPv4 inet_ntoa()
+            *  eg. 127.0.0.1 (IPv4) or ::1 (IPv6)
+            *  But for memory safety it requires a buffer as input
+            *  instead of producing one magically.
+            *  If buffer is not large enough the data is truncated silently.
+            * \param buf Allocated buffer to write address to
+            * \param len byte length of buffer available for writing.
+            * \return pointer to buffer received.
+            */
+    char* NtoA(char *buf, unsigned int len) const;
+
+           /** Return the ASCII equivalent of the address:port combination
+            *  Provides a URL formatted version of the content.
+            *  If buffer is not large enough the data is truncated silently.
+            *  eg. 127.0.0.1:80 (IPv4) or [::1]:80 (IPv6)
+            * \param buf Allocated buffer to write address:port to
+            * \param len byte length of buffer available for writing.
+            * \return pointer to buffer received.
+            */
+    char* ToURL(char *buf, unsigned int len) const;
+
+           /** \fn bool GetReverseString(char buf[], IPAddressType show_format)
+            *  Convert the content into a Reverse-DNS string.
+            *  The buffer sent MUST be allocated large enough to hold the resulting string.
+            *  Name truncation will occur if buf does not have enough space.
+            *  The constant MAX_IPSTRLEN is defined to provide for sizing arrays correctly.
+            *  \param show_format may be one of: IPv4,IPv6 for the format of rDNS string wanted.
+            *  \param buf buffer to receive the text string output.
+            */
+#ifdef USE_IPV6
+    bool GetReverseString(char buf[], IPAddressType show_format = IPv6) const;
+#else
+    bool GetReverseString(char buf[], IPAddressType show_format = IPv4) const;
+#endif
+
+#ifdef _GLIBCXX_IOSTREAM
+    std::ostream& operator<<(std::ostream& os) const;
+#endif
+
+
+public:
+    /* FIXME: When C => C++ conversion is done will be fully private.
+     * Legacy Transition Methods
+     * These are here solely to simplify the transition
+     * when moving from converted code to unconverted
+     * these functions can be used to convert this object
+     * and pull out the data needed by the unconverted code
+     * they are intentionaly hard to use, to encourage less use.
+     */
+
+    void GetSockAddr(struct sockaddr_in &) const;
+    bool GetInAddr(struct in_addr &) const; /* false if could not convert IPv6 down to IPv4 */
+#ifdef USE_IPV6
+    void GetSockAddr(struct sockaddr_in6 &) const;
+    void GetInAddr(struct in6_addr &) const;
+#endif
+
+private:
+    int matchIPAddr(const IPAddress &rhs) const;
+    /* Conversion for dual-type internals */
+    bool GetReverseString4(char buf[], struct in_addr &) const;
+#ifdef USE_IPV6
+    void check4Mapped();
+    bool GetReverseString6(char buf[], struct in6_addr &) const;
+    void Map4to6(const struct in_addr &src, struct in6_addr &dest) const;
+    void Map6to4(const struct in6_addr &src, struct in_addr &dest) const;
+#endif
+
+  /* variables */
+    IPAddressType m_Type;
+#ifdef USE_IPV6
+    struct sockaddr_in6 m_SocketAddr;
+#else
+    struct sockaddr_in m_SocketAddr;
+#endif
+};
+
+#endif /* _INC_IPADDRESS_H */
Index: squid3/include/util.h
diff -u squid3/include/util.h:1.15 squid3/include/util.h:1.10.8.10
--- squid3/include/util.h:1.15	Sat Oct 14 06:51:15 2006
+++ squid3/include/util.h	Thu Apr  5 02:26:32 2007
@@ -43,6 +43,7 @@
 #if HAVE_SYS_TIME_H
 #include <sys/time.h>
 #endif
+#include <arpa/inet.h>
 
 #if !defined(SQUIDHOSTNAMELEN)
 #define SQUIDHOSTNAMELEN 256
@@ -123,8 +124,7 @@
 extern void xmalloc_find_leaks(void);
 #endif
 
-typedef struct IN_ADDR SIA;
-SQUIDCEXTERN int safe_inet_addr(const char *, SIA *);
+SQUIDCEXTERN int safe_inet_addr(const char *, struct in_addr *);
 SQUIDCEXTERN time_t parse_iso3307_time(const char *buf);
 SQUIDCEXTERN char *base64_decode(const char *coded);
 SQUIDCEXTERN const char *base64_encode(const char *decoded);
Patch file generated Sat Apr  7 15:26:59 NZST 2007 from
CVS branch squid3-ipv6
CVS base branch HEAD
CVS repository: [EMAIL PROTECTED]:/cvsroot/squid
CVS module: squid3/lib

cvs -q rdiff -u -kk -r Z-squid3-ipv6_merge_HEAD -r squid3-ipv6 squid3/lib
Index: squid3/lib/IPAddress.cc
diff -u /dev/null squid3/lib/IPAddress.cc:1.1.2.19
--- /dev/null		Thu Jan  1 01:00:00 1970
+++ squid3/lib/IPAddress.cc	Thu Apr  5 03:51:40 2007
@@ -0,0 +1,647 @@
+/*
+ * $Id$
+ */
+#include "IPAddress.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netinet/in.h> /* inet Macros	*/
+#include <arpa/inet.h>	/* inet_ntoa()	*/
+#include <netdb.h>
+
+#include "util.h"
+
+#ifdef INET6
+#error "INET6 defined but has been deprecated! Try running bootstrap and configure again."
+#endif
+
+/* We want to use the debug routines when running as module of squid. */
+/* otherwise fallback to printf if those are not available. */
+#ifndef SQUID_DEBUG
+#    define debug(a,b)	printf
+#else
+#    include "../Debug.h"
+#endif
+
+/*
+    enum IPAddressType {
+            NONE=0,
+            SockAddr =1, // Full SocketAddr Details Stored.
+            IPv4     =2, // Pure IPv4 address stored (conversion up must be done explicitly)
+            IPv6     =4, // Pure IPv6 Address Stored (no conversion to IPv4 possible)
+            IPv64    =6  // Dual-Address Stored (can return either IPv6 OR IPv4)
+    } m_Type;
+    struct sockaddr m_SocketAddr;
+*/
+
+#ifndef USE_IPV6
+// AYJ: So there are some places where I will drop to using Macros too.
+//      At least I can restrict them to this file so they don't corrupt the app with C code.
+#  define sin6_addr	sin_addr
+#  define sin6_port	sin_port
+#endif
+
+static const unsigned int STRLEN_IP4A = 16;              // aaa.bbb.ccc.ddd\0
+static const unsigned int STRLEN_IP4R = 28;              // ddd.ccc.bbb.aaa.in-addr.arpa.\0
+static const unsigned int STRLEN_IP4S = 21;              // ddd.ccc.bbb.aaa:ppppp\0
+static const unsigned int MAX_IP4_STRLEN = STRLEN_IP4R;
+static const unsigned int STRLEN_IP6A = 42;           // [ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]/0
+static const unsigned int STRLEN_IP6R = 75;           // f.f.f.f f.f.f.f f.f.f.f f.f.f.f f.f.f.f f.f.f.f f.f.f.f f.f.f.f ipv6.arpa./0
+static const unsigned int STRLEN_IP6S = 48;           // [ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]:00000/0
+static const unsigned int MAX_IP6_STRLEN = STRLEN_IP6R;
+
+
+IPAddress::IPAddress()
+{
+    memset(this,0,sizeof(IPAddress));
+#ifdef USE_IPV6
+    m_Type = IPv64;
+#else 
+    m_Type = IPv4;
+#endif
+}
+IPAddress::~IPAddress()
+{
+    memset(this,0,sizeof(IPAddress));
+}
+const int IPAddress::ApplyMask(IPAddress const &mask_addr)
+{
+    uint32_t *p1 = (uint32_t*)(&m_SocketAddr.sin6_addr);
+    uint32_t const *p2 = (uint32_t const *)(&mask_addr.m_SocketAddr.sin6_addr);
+    unsigned int blen = sizeof(m_SocketAddr.sin6_addr)/sizeof(uint32_t);
+    unsigned int changes = 0;
+
+    for (unsigned int i = 0; i < blen; i++) {
+        if((p1[i] & p2[i]) != p1[i]) changes++;
+        p1[i] &= p2[i];
+    }
+    return changes;
+}
+bool IPAddress::ApplyMask(const unsigned int icidr, IPAddressType mtype)
+{
+    uint8_t clearbits = 0;
+    uint8_t* p = NULL;
+    unsigned int cidr = icidr;
+
+#ifdef USE_IPV6 /* IPv6 has IPv4 as Mapped-address */
+    if (cidr > 128) return false;
+#else
+    if (cidr > 32) return false;
+#endif
+    if(cidr < 0) return true; // any err like this can be assumed /0
+
+    clearbits = (uint8_t)((m_Type&IPv6?128:32)-cidr);
+
+#ifdef USE_IPV6
+    p = (uint8_t*)(&m_SocketAddr.sin6_addr) + 15;
+#else
+    p = (uint8_t*)(&m_SocketAddr.sin6_addr) + 3;
+#endif
+
+    for (; clearbits>0 && p >= (uint8_t*)&m_SocketAddr.sin6_addr ; clearbits-=8, p-- ) {
+        *p &= ((0xFF << clearbits) & 0xFF);
+    }
+
+    return true;
+}
+
+bool IPAddress::IsAnyAddr() const
+{
+#ifdef USE_IPV6
+    return     m_SocketAddr.sin6_addr.s6_addr32[0] == 0
+            && m_SocketAddr.sin6_addr.s6_addr32[1] == 0
+            && m_SocketAddr.sin6_addr.s6_addr32[2] == 0
+            && m_SocketAddr.sin6_addr.s6_addr32[3] == 0
+    ;
+#else
+	return (INADDR_ANY == m_SocketAddr.sin_addr.s_addr);
+#endif
+}
+void IPAddress::SetAnyAddr()
+{
+    memset(&(m_SocketAddr.sin6_addr),0, sizeof(m_SocketAddr.sin6_addr));
+#ifdef USE_IPV6
+    m_Type = IPv64;
+#else
+    m_Type=IPv4;
+#endif
+}
+void IPAddress::SetEmpty()
+{
+    memset(&(m_SocketAddr.sin6_addr),0x0, sizeof(m_SocketAddr.sin6_addr));
+}
+
+bool IPAddress::IsNoAddr() const
+{
+    // IFF the address == 0xff..ff (all ones)
+#ifdef USE_IPV6
+    return     m_SocketAddr.sin6_addr.s6_addr32[0] == 0xFFFFFFFF
+            && m_SocketAddr.sin6_addr.s6_addr32[1] == 0xFFFFFFFF
+            && m_SocketAddr.sin6_addr.s6_addr32[2] == 0xFFFFFFFF
+            && m_SocketAddr.sin6_addr.s6_addr32[3] == 0xFFFFFFFF
+    ;
+#else
+    return 0xFFFFFFFF == m_SocketAddr.sin_addr.s_addr;
+#endif
+}
+void IPAddress::SetNoAddr()
+{
+    memset(&(m_SocketAddr.sin6_addr),0xFFFFFFFF,sizeof(m_SocketAddr.sin6_addr));
+#ifdef USE_IPV6
+    m_Type = IPv64;
+#else
+    m_Type=IPv4;
+#endif
+}
+
+#ifdef USE_IPV6
+bool IPAddress::GetReverseString6(char buf[MAX_IPSTRLEN], struct in6_addr &dat) const
+{
+    char *p = buf;
+    unsigned char *r = dat.s6_addr;
+
+    /* RFC1886 says: */
+    /*     4321:0:1:2:3:4:567:89ab */
+    /*     must be sent */
+    /*     b.a.9.8.7.6.5.0.4.0.0.0.3.0.0.0.2.0.0.0.1.0.0.0.0.0.0.0.1.2.3.4.ip6.int. */
+
+    /* Work from the binary field. Anything else may have representation changes. */
+    /* The sin6_port and sin6_addr members shall be in network byte order. */
+
+    /* Compile Err: 'Too many arguments for format. */
+    for(int i = 15; i >= 0; i--, p+=4)
+    {
+        snprintf(p, 5, "%x.%x.", (((r[i])>>4)&0xf), ((r[i])&0xf) );
+    }
+
+    /* RFC3152 says: */
+    /*     ip6.int is now deprecated TLD, use ip6.arpa instead. */
+    snprintf(p,10,"ip6.arpa.");
+
+    return true;
+}
+#endif
+
+bool IPAddress::GetReverseString4(char buf[MAX_IPSTRLEN], struct in_addr &dat) const
+{
+    unsigned int i = (unsigned int) ntohl(dat.s_addr);
+    snprintf(buf, 32, "%u.%u.%u.%u.in-addr.arpa.",
+                 i & 255,
+                 (i >> 8) & 255,
+                 (i >> 16) & 255,
+                 (i >> 24) & 255);
+    return true;
+}
+
+bool IPAddress::GetReverseString(char buf[MAX_IPSTRLEN], IPAddressType show_type) const
+{
+    in_addr* ip4_ptr = NULL;
+#ifdef USE_IPV6
+    in6_addr* ip6_ptr = NULL;
+    in6_addr tmp_buf;
+#endif
+
+    if(m_Type == None) return false;
+#ifdef USE_IPV6
+    if(show_type == None) show_type = IPv6;
+#else
+    if(show_type == None) show_type = IPv4;
+#endif
+
+    switch(m_Type & IPv64) // What we do depends on how we stored it.
+    {
+        case IPv4:
+#ifndef USE_IPV6
+            ip4_ptr = (in_addr*)&m_SocketAddr.sin_addr;
+#else /* USE_IPV6 */
+            ip4_ptr = (in_addr*)&m_SocketAddr.sin6_addr.s6_addr[12];
+            ip6_ptr = &tmp_buf;
+            Map4to6(*ip4_ptr, *ip6_ptr);
+#endif
+        break;
+
+        case IPv64:
+#ifndef USE_IPV6
+            ip4_ptr = (in_addr*)&m_SocketAddr.sin_addr;
+#else
+            ip4_ptr = (in_addr*)&m_SocketAddr.sin6_addr.s6_addr32[3];
+            // Fall through to setup IPv6 output ptr
+
+        case IPv6:
+            ip6_ptr = (in6_addr*)&m_SocketAddr.sin6_addr;
+#endif
+        break;
+    }
+
+    if(show_type == IPv4 && ip4_ptr != NULL)
+    {
+        return GetReverseString4(buf, *(in_addr*)ip4_ptr);
+    }
+#ifdef USE_IPV6
+    if(show_type == IPv6 && ip6_ptr != NULL)
+    {
+        return GetReverseString6(buf, *(in6_addr*)ip6_ptr);
+    }
+#endif
+
+    debug(14,1)("IPAddress::GetReverseString : Address stored cannot be converted to type requested.\n");
+    buf[0] = '\0';
+    return false;
+}
+
+IPAddress& IPAddress::operator =(const IPAddress &s) {
+    memcpy(this, &s, sizeof(IPAddress));
+    return *this;
+};
+
+IPAddress::IPAddress(const char*s)
+{
+    memset(this,0,sizeof(IPAddress));
+    operator=(s);
+}
+
+bool IPAddress::operator =(const char* s)
+{
+    struct hostent *hp = NULL;
+
+    if ((hp = gethostbyname(s)) == NULL) {
+        debug(14,1)("IPAddress:::operator= : Given Bad IP '%s'\n", s);
+        return false;
+    }
+
+    if(hp->h_addrtype == AF_INET)
+        operator=( *((struct in_addr*)hp->h_addr_list[0]) );
+#ifdef USE_IPV6
+    else if(hp->h_addrtype == AF_INET6)
+        operator=( *((struct in6_addr*)hp->h_addr_list[0]) );
+#endif
+    else
+    {
+        debug(14,1)("IPAddress::operator=(hostent*) : Discarding IP address '%s'.\n",s);
+        return false;
+    }
+    return true;
+}
+
+
+IPAddress::IPAddress(struct sockaddr_in const &s) {
+    memset(this,0,sizeof(IPAddress));
+    operator=(s);
+};
+IPAddress& IPAddress::operator =(struct sockaddr_in const &s) {
+#ifdef USE_IPV6
+    Map4to6((const in_addr)s.sin_addr, m_SocketAddr.sin6_addr);
+    m_SocketAddr.sin6_port = s.sin_port;
+    m_SocketAddr.sin6_family = AF_INET6;
+    m_Type=(IPAddressType)(IPv64 | SockAddr);
+#else
+    memcpy(&m_SocketAddr, &s, sizeof(struct sockaddr_in));
+    m_Type=(IPAddressType)(IPv4 | SockAddr);
+#endif
+    return *this;
+};
+
+#ifdef USE_IPV6
+void IPAddress::check4Mapped()
+{
+    /* check for  ::ffff:x.x.x.x IPv4-mapped addresses */
+    if( 0 == memcmp(&m_SocketAddr.sin6_addr, &"\0x00000000\0x00000000\0x00000000\0xFFFF", sizeof(struct in6_addr)-sizeof(struct in_addr) ) )
+    {
+        m_Type = (IPAddressType)(m_Type | IPv4);
+    }
+    if( 0 == memcmp(&m_SocketAddr.sin6_addr, &"\0x00000000\0x00000000\0x00000000\0x00000000", sizeof(struct in6_addr) ) )
+    {
+        m_Type = (IPAddressType)(m_Type | IPv4);
+    }
+    if( 0 == memcmp(&m_SocketAddr.sin6_addr, &"\0xFFFFFFFF\0xFFFFFFFF\0xFFFFFFFF\0xFFFFFFFF", sizeof(struct in6_addr) ) )
+    {
+        m_Type = (IPAddressType)(m_Type | IPv4);
+    }
+    /* FIXME INET6 : maybe other tests can apply if the IPA was mapped in other ways */
+    /*        I know of 2002:0.0.0.0:: mappings and possibly fe80::???? mappings */
+
+}
+
+IPAddress::IPAddress(sockaddr_in6 const &s) {
+    memset(this,0,sizeof(IPAddress));
+    operator=(s);
+};
+IPAddress& IPAddress::operator =(sockaddr_in6 const &s) {
+    memcpy(&m_SocketAddr, &s, sizeof(struct sockaddr_in6));
+    m_Type = (IPAddressType)(SockAddr | IPv6);
+
+    check4Mapped();
+    return *this;
+};
+#endif
+
+IPAddress::IPAddress(in_addr const &s) {
+    memset(this,0,sizeof(IPAddress));
+    operator=(s);
+};
+IPAddress& IPAddress::operator =(in_addr const &s) {
+#ifdef USE_IPV6
+    Map4to6((const in_addr)s, m_SocketAddr.sin6_addr);
+    m_SocketAddr.sin6_family = AF_INET6;
+    if(m_SocketAddr.sin6_port > 0)
+        m_Type=(IPAddressType)(SockAddr | IPv64);
+    else
+        m_Type=IPv64;
+#else
+    memcpy(&m_SocketAddr.sin_addr, &s, sizeof(struct in_addr));
+    m_SocketAddr.sin_family = AF_INET;
+    if(m_SocketAddr.sin_port > 0)
+        m_Type=(IPAddressType)(SockAddr | IPv4);
+    else
+        m_Type=IPv4;
+#endif
+    return *this;
+};
+
+#ifdef USE_IPV6
+IPAddress::IPAddress(struct in6_addr const &s) {
+    memset(this,0,sizeof(IPAddress));
+    operator=(s);
+};
+IPAddress& IPAddress::operator =(struct in6_addr const &s) {
+    memcpy(&m_SocketAddr.sin6_addr, &s, sizeof(struct in6_addr));
+    m_SocketAddr.sin6_family = AF_INET6;
+    if(m_SocketAddr.sin6_port > 0)
+        m_Type=(IPAddressType)(SockAddr | IPv6);
+    else
+        m_Type=IPv6;
+
+    check4Mapped();
+    return *this;
+};
+#endif
+
+IPAddress::IPAddress(const IPAddress &s) {
+    memset(this,0,sizeof(IPAddress));
+    operator=(s);
+}
+
+IPAddress::IPAddress(const struct hostent *s) {
+    memset(this,0,sizeof(IPAddress));
+    operator=(s);
+}
+
+bool IPAddress::operator =(const struct hostent *s)
+{
+    struct in_addr* ipv4 = NULL;
+    struct in6_addr* ipv6 = NULL;
+
+//struct hostent {
+//        char    *h_name;        /* official name of host */
+//        char    **h_aliases;    /* alias list */
+//        int     h_addrtype;     /* host address type */
+//        int     h_length;       /* length of address */
+//        char    **h_addr_list;  /* list of addresses */
+//}
+
+    switch(s->h_addrtype)
+    {
+    case AF_INET:
+        ipv4 = (in_addr*)(s->h_addr_list[0]);
+        /* this */ operator=(*ipv4);
+        break;
+    case AF_INET6:
+        ipv6 = (in6_addr*)(s->h_addr_list[0]);
+#ifdef USE_IPV6
+        /* this */ operator=(*ipv6);
+#else
+        debug(14,1)("IPAddress::operator= : Discarded IPv6 Address. Protocol disabled.\n");
+
+        // TODO see if there is another address in the list that might be usable ??
+        return false;
+#endif
+        break;
+    }
+
+    return true;
+}
+
+#ifdef _GLIBCXX_IOSTREAM
+/// Operator to output ASCII version of Address:Port to a ostream
+std::ostream& IPAddress::operator<<(std::ostream& os) const
+{
+    char buf[MAX_IPSTRLEN];
+    // Dump the Current [Address]:Port to the debug stream.
+#ifdef USE_IPV6
+    if(IsIPv6())
+#else
+    if(false)
+#endif
+        os << "[" << NtoA(buf,MAX_IPSTRLEN) << "]:" << m_SocketAddr.sin6_port;
+    else
+        os << NtoA(buf,MAX_IPSTRLEN) << ":" << m_SocketAddr.sin6_port;
+
+    return os;
+}
+#endif
+
+int IPAddress::matchIPAddr(const IPAddress &rhs) const
+{
+    unsigned int slen = sizeof(m_SocketAddr.sin6_addr);
+    uint8_t *l = (uint8_t*)&m_SocketAddr.sin6_addr;
+    uint8_t *r = (uint8_t*)&rhs.m_SocketAddr.sin6_addr;
+    uint8_t *end = l+slen;
+
+    // loop a bit-wise compare
+    for( ; l <= end ; r++, l++)
+    {
+        if(*l < *r) return -1;
+        if(*l > *r) return 1;
+    }
+    return true;
+}
+
+bool IPAddress::operator ==(const IPAddress &s) const
+{
+    if(m_Type != s.m_Type) return false;
+    return (0 == matchIPAddr(s));
+}
+bool IPAddress::operator <=(const IPAddress &rhs) const
+{
+    if(IsAnyAddr() && !rhs.IsAnyAddr()) return true;
+    return (matchIPAddr(rhs) <= 0);
+}
+
+bool IPAddress::operator >=(const IPAddress &rhs) const
+{
+    if(IsNoAddr() && !rhs.IsNoAddr()) return true;
+    return ( matchIPAddr(rhs) >= 0);
+}
+
+u_short IPAddress::GetPort() const
+{
+    return ntohs( m_SocketAddr.sin6_port );
+}
+
+u_short IPAddress::SetPort(u_short prt)
+{
+    m_SocketAddr.sin6_port = htons(prt);
+    if(m_Type != None) m_Type = (IPAddressType)(m_Type | SockAddr);
+    return prt;
+}
+
+/**
+ * NtoA Given a buffer writes a readable ascii version of the IPA and/or port stored
+ *
+ * Buffer must be of a size large enough to hold the converted address.
+ * This size if provided in the form of a defined variable MAX_IPSTRLEN
+ * Should a buffer shorter be provided the string result will be truncated
+ * at the length of the available buffer.
+ *
+ * A copy of the buffer is also returned for simple immediate display.
+ */
+char* IPAddress::NtoA(char* buf, unsigned int blen) const
+{
+    // Ensure we have a buffer.
+    if(buf == NULL)
+    {
+        debug(14,1)("IPAddress::NtoA : Buffer received has no allocated space.\n");
+        return NULL;
+    }
+    memset(buf,0,blen);
+
+    if(m_Type & IPv6 )
+        inet_ntop(AF_INET6, &m_SocketAddr.sin6_addr, buf, blen);
+    else
+        inet_ntop(AF_INET, &m_SocketAddr.sin6_addr, buf, blen);
+
+    return buf;
+}
+
+char* IPAddress::ToURL(char* buf, unsigned int blen) const
+{
+    char *p = buf;
+
+    // Ensure we have a buffer.
+    if(buf == NULL)
+    {
+        debug(14,1)("IPAddress::ToURL : Buffer received has no allocated space.\n");
+        return NULL;
+    }
+
+    memset(buf,0,blen);
+
+#ifdef USE_IPV6
+    if(blen > 0) {
+        *p = '[';
+        p++;
+    }
+#endif
+
+    /* 7 being space for [,], and port */
+    p = NtoA(p, blen-7);
+
+    // find the end of the new string
+    while(*p != '\0' && p < buf+blen) p++;
+
+#ifdef USE_IPV6
+    if(p < buf+blen-1) {
+        *p = ']';
+        p++;
+    }
+#endif
+
+    if(m_SocketAddr.sin6_port > 0 && p < buf+blen-6)
+    {
+        /* 6 is max length of expected ':port' (short int) */
+        snprintf(p,6,":%d", GetPort() );
+    }
+
+    // force a null-terminated string
+    buf[blen] = '\0';
+
+    return buf;
+}
+
+void IPAddress::GetSockAddr(struct sockaddr_in &buf) const
+{
+#ifdef USE_IPV6
+    if(m_Type & IPv4) // if can be converted down.
+    {
+        buf.sin_family = AF_INET;
+        buf.sin_port = m_SocketAddr.sin6_port;
+        Map6to4( m_SocketAddr.sin6_addr, buf.sin_addr);
+    }
+    else // no conversion. set it to invalid content.
+    {
+        memset(&buf, 0, sizeof(struct sockaddr_in));
+    }
+#else
+    memcpy(&buf, &m_SocketAddr, sizeof(struct sockaddr_in));
+#endif
+}
+
+#ifdef USE_IPV6
+void IPAddress::GetSockAddr(struct sockaddr_in6 &buf) const
+{
+    memcpy(&buf, &m_SocketAddr, sizeof(struct sockaddr_in6));
+    buf.sin6_family = AF_INET6;
+}
+#endif
+
+#ifdef USE_IPV6
+void IPAddress::Map4to6(const struct in_addr &in, struct in6_addr &out) const
+{
+    /* check for special cases */
+    if( in.s_addr == 0x00000000)
+    {
+        memset(&out, 0, sizeof(struct in6_addr));
+    }
+    else if( in.s_addr == 0xFFFFFFFF)
+    {
+        out.s6_addr32[0] = 0xFFFFFFFF;
+        out.s6_addr32[1] = 0xFFFFFFFF;
+        out.s6_addr32[2] = 0xFFFFFFFF;
+        out.s6_addr32[3] = 0xFFFFFFFF;
+    }
+    /* FIXME TODO : handle special case of localhost (IPv4 127.0.0.1, IPv6 ::1 ) */
+    else
+    {
+        memset(&out, 0, sizeof(struct in6_addr));
+        out.s6_addr32[3] = in.s_addr;
+        out.s6_addr16[5] = (unsigned short)0xFFFF;
+    }
+}
+void IPAddress::Map6to4(const struct in6_addr &in, struct in_addr &out) const
+{
+    /* FIXME TODO : handle special case of localhost (IPv4 127.0.0.1, IPv6 ::1 ) */
+    memset(&out, 0, sizeof(struct in_addr));
+    out.s_addr = in.s6_addr32[3];
+}
+#endif
+
+#ifdef USE_IPV6
+void IPAddress::GetInAddr(in6_addr &buf) const
+{
+    assert(m_Type & IPv6);
+    memcpy(&buf, &m_SocketAddr.sin6_addr, sizeof(struct in6_addr));
+}
+#endif
+
+bool IPAddress::GetInAddr(struct in_addr &buf) const
+{
+    switch(m_Type & IPv64)
+    {
+#ifdef USE_IPV6
+        case IPv64: // IPv4-Compatible IPv6 Address
+            Map6to4((const in6_addr)m_SocketAddr.sin6_addr, buf);
+        return true;
+#else
+        case IPv4: // Pure IPv4 Address.
+            memcpy(&buf, &m_SocketAddr.sin_addr,  sizeof(struct in_addr));
+        return true;
+#endif
+
+        case IPv6: // non-compatible IPv6 Pure Address
+        default:
+            debug(14,1)("IPAddress::GetInAddr : Cannot convert non-IP to IPv4.\n");
+            memset(&buf,0xFFFFFFFF,sizeof(struct in_addr));
+        return false;
+    }
+}
Index: squid3/lib/Makefile.am
diff -u squid3/lib/Makefile.am:1.17 squid3/lib/Makefile.am:1.12.4.2
--- squid3/lib/Makefile.am:1.17	Sat Sep  2 06:52:12 2006
+++ squid3/lib/Makefile.am	Sun Mar 18 02:07:02 2007
@@ -65,6 +65,7 @@
 	hash.c \
 	heap.c \
 	html_quote.c \
+	IPAddress.cc \
 	iso3307.c \
 	$(MD5SOURCE) \
 	radix.c \
Index: squid3/lib/rfc1035.c
diff -u squid3/lib/rfc1035.c:1.11 squid3/lib/rfc1035.c:1.5.2.14
--- squid3/lib/rfc1035.c:1.11	Wed May 11 19:13:16 2005
+++ squid3/lib/rfc1035.c	Wed Apr  4 01:15:16 2007
@@ -671,7 +671,7 @@
  * Returns the size of the query
  */
 ssize_t
-rfc1035BuildPTRQuery(const struct IN_ADDR addr, char *buf, size_t sz, unsigned short qid, rfc1035_query * query)
+rfc1035BuildPTRQuery(const struct in_addr addr, char *buf, size_t sz, unsigned short qid, rfc1035_query * query)
 {
     static rfc1035_message h;
     size_t offset = 0;
@@ -746,7 +746,7 @@
     S.sin_port = htons(atoi(argv[2]));
     S.sin_addr.s_addr = inet_addr(argv[1]);
     while (fgets(input, 512, stdin)) {
-	struct IN_ADDR junk;
+	struct in_addr junk;
 	strtok(input, "\r\n");
 	memset(buf, '\0', 512);
 	sz = 512;
@@ -788,7 +788,7 @@
 		printf("%d answers\n", n);
 		for (i = 0; i < n; i++) {
 		    if (answers[i].type == RFC1035_TYPE_A) {
-			struct IN_ADDR a;
+			struct in_addr a;
 			memcpy(&a, answers[i].rdata, 4);
 			printf("A\t%d\t%s\n", answers[i].ttl, inet_ntoa(a));
 		    } else if (answers[i].type == RFC1035_TYPE_PTR) {

Reply via email to