Patch file generated Sat Apr 7 15:26:59 NZST 2007 from CVS branch squid3-ipv6 CVS base branch HEAD CVS repository: amosjeffries@cvs.devel.squid-cache.org:/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 +#include +#include +#include /* inet Macros */ +#include /* inet_ntoa() */ +#include + +#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) {