netprotectaddr.cc #1

  • //
  • guest/
  • perforce_software/
  • p4/
  • 2016-1/
  • net/
  • netprotectaddr.cc
  • View
  • Commits
  • Open Download .zip Download (7 KB)
// -*- mode: C++; tab-width: 8; -*-
// vi:ts=8 sw=4 noexpandtab autoindent

/**
 * netprotectaddr.h - Store an IPv4 or IPv6 protects table address and compare it with match strings.
 *
 * Copyright 2012 Perforce Software.  All rights reserved.
 *
 * This file is part of Perforce - the FAST SCM System.
 */

#include <stdhdrs.h>
#include <strbuf.h>
#include "netport.h"
#include "netportipv6.h"
#include "netipaddr.h"
#include "netprotectaddr.h"

// uncomment to enable address parse/match debugging
//#define NPA_DEBUG

#ifdef NPA_DEBUG
  #include "debug.h"
#endif

/*
 * Orthodox Canonical Form (OCF) methods
 */


/**
 * default ctor
 */
NetProtectAddr::NetProtectAddr()
: m_proxy(PROXY_NONE)
, m_addr()
, m_prefixlen(NetIPAddr::CIDR_UNSPEC)
, m_type(NetProtectAddr::PROT_ADDR_TEXT)
{
} // default ctor

NetProtectAddr::NetProtectAddr(
	const StrPtr &addr)
: m_proxy(PROXY_NONE)
, m_addr(addr)
, m_prefixlen(NetIPAddr::CIDR_UNSPEC)
, m_type(NetProtectAddr::PROT_ADDR_TEXT)
{
	Parse();
}

/**
 * copy ctor
 */
NetProtectAddr::NetProtectAddr(
	const NetProtectAddr	&rhs)
: m_proxy(rhs.m_proxy)
, m_addr(rhs.m_addr)
, m_prefixlen(rhs.m_prefixlen)
, m_type(rhs.m_type)
, m_nipa(rhs.m_nipa)
{
} // copy ctor

/**
 * dtor
 */
NetProtectAddr::~NetProtectAddr()
{
} // dtor

/**
 * assignment op
 */
const NetProtectAddr	&
NetProtectAddr::operator=(
	const NetProtectAddr	&rhs)
{
	if( this != &rhs ) {
	    m_proxy = rhs.m_proxy;
	    m_addr = rhs.m_addr;
	    m_prefixlen = rhs.m_prefixlen;
	    m_type = rhs.m_type;
	    m_nipa = rhs.m_nipa;
	}

	return *this;
} // op=

/**
 * op==
 */
bool
NetProtectAddr::operator==(
	const NetProtectAddr	&rhs) const
{
	if( this == &rhs ) {
	        return true;
	}

	if( m_proxy != rhs.m_proxy
	    || m_addr != rhs.m_addr
	    || m_prefixlen != rhs.m_prefixlen
	    || m_type != rhs.m_type
	    || m_nipa != rhs.m_nipa )
	{
	    return false;
	}

	return true;
} // op==

/**
 * op!=
 */
bool
NetProtectAddr::operator!=(
	const NetProtectAddr	&rhs) const
{
	return !(*this == rhs);
} // op!=


/*
 * Other methods
 */


/**
 * Parse a string into its components:
 * regex:
 *    [proxy-]Address[/[pfxlen]]
 * BNF:
 *    ProtectEntry    ::= OptProxyPrefix Address OptPrefixLen ;
 *    OptProxyPrefix  ::= 'proxy-'
 *                    |
 *                    ;
 *    Address         ::= IPv4Address
 *                    | IPv6Address 
 *                    | WildAddress
 *                    ;
 *    IPv4Address     ::= [0-9]{1,3}.[0-9]{1,3}.[0-9]{0,3}.[0-9]{0,3} ;
 *    IPv6Address     ::= // I won't describe IPv6 in a single regex! 8 fields of 16 bits: [0-9a-fA-F]{0,4} ;
 *    WildAddress     := * ;    // any text string; '*' is special
 *    OptPrefixLen    ::= '/' number
 *                    | '/'
 *                    |
 *                    ;
 */
void
NetProtectAddr::Parse()
{
	const char *cp = m_addr.Text();
	StrBuf tmpbuf; // used to avoid overlapping src/dst in StrBuf::Set() calls

	// check for a proxy prefix
	if( !StrRef("proxy-").XCompareN(m_addr) )
	{
	    m_proxy = PROXY_SET;
	    cp += 6;	// skip the proxy stuff
	}
	else if( *cp == '*' )
	{
	    m_proxy = PROXY_OPT;
	    cp++;	// skip the optional proxy flag
	}
	else
	{
	    m_proxy = PROXY_NONE;
	}

	// check for a netmask (network prefix len in "slash" notation)
	if( const char *p = strchr(cp, '/') )
	{
	    tmpbuf.Set( cp, p - cp );
	    m_addr.Set( tmpbuf.Text() );
	    m_prefixlen = StrPtr::Atoi( p + 1 );

	    // pin cidr values to the allowed range boundaries
	    if( m_prefixlen < NetIPAddr::CIDR_MIN )
	        m_prefixlen = NetIPAddr::CIDR_MIN;
	    else if( m_prefixlen > NetIPAddr::CIDR_MAX_V6 )
	        m_prefixlen = NetIPAddr::CIDR_MAX_V6;
	}
	else
	{
	    m_prefixlen = NetIPAddr::CIDR_UNSPEC;
	    tmpbuf.Set( cp );
	    m_addr.Set( tmpbuf.Text() );
	}

	m_nipa.Set(m_addr, m_prefixlen);
	if( m_nipa.IsTypeV4() )
	{
	    m_type = PROT_ADDR_V4;
	    if( m_prefixlen > NetIPAddr::CIDR_MAX_V4 )
	        m_prefixlen = NetIPAddr::CIDR_MAX_V4;
	}
	else if( m_nipa.IsTypeV6() )
	{
	    m_type = PROT_ADDR_V6;
	    if( m_prefixlen > NetIPAddr::CIDR_MAX_V6 )
	        m_prefixlen = NetIPAddr::CIDR_MAX_V6;
	}
	else
	{
	    // optimize common case
	    if( m_addr == "*" )
	        m_type = PROT_ADDR_ANY;
	    else
	        m_type = PROT_ADDR_TEXT;
	    m_prefixlen = NetIPAddr::CIDR_UNSPEC;
	}
}


bool
NetProtectAddr::Match( const NetProtectAddr &rhs ) const
{
#ifdef NPA_DEBUG
	StrBuf	buf;
	StrBuf	rhsbuf;

	ToString(buf);
	rhs.ToString(rhsbuf);
	p4debug.printf( "  NetProtectAddr::Match(%s, %s)\n", buf.Text(), rhsbuf.Text() );
#endif

	if( !m_nipa.IsTypeValid() )
	    return false;

	switch( rhs.m_proxy )
	{
	case PROXY_NONE:
	    if( m_proxy == PROXY_SET )
	        return false;
	    break;
	case PROXY_SET:
	    if( m_proxy == PROXY_NONE )
	        return false;
	    break;
	case PROXY_OPT:
	    // fall through
	    break;
	}

	switch( rhs.m_type )
	{
	case PROT_ADDR_ANY:
	    // short-circuit most common case
	    return true;
	case PROT_ADDR_V4:
	case PROT_ADDR_V6:
	    return m_nipa.Match(rhs.m_nipa);
	case PROT_ADDR_TEXT:
	    return false;	// caller must handle [opt wildcard] text, eg, by calling MatchTable::Match()
	}

	return false;
}

/**
 * Match
 * Common usage (eg, from dmprotects.cc):
 * NetProtectAddr npa( myhostaddress );
 * while (entry = get next protect table entry)
 * {
 *     if( npa.Match(entry.host) )
 *     {
 *         ...
 *     }
 * }
 */
bool
NetProtectAddr::Match( const StrPtr &cidr ) const
{
#ifdef NPA_DEBUG
	StrBuf buf;

	ToString(buf);
	p4debug.printf( "  NetProtectAddr::Match(\"%s\") against %s\n", buf.Text(), cidr.Text() );
#endif

	const NetProtectAddr npa( cidr );

	return Match(npa);
}

/*
 * Debugging -- generate a textual representation of the address type
 * [static]
 */
const char *
NetProtectAddr::TypeName(ProtAddrType t)
{
	switch( t )
	{
	case PROT_ADDR_V4:	return "v4";
	case PROT_ADDR_V6:	return "v6";
	case PROT_ADDR_TEXT:	return "txt";
	case PROT_ADDR_ANY:	return "*";
	}

	// quiet warning c4715: not all control paths return a value
	return "<unknown>";
}

/*
 * Debugging -- generate a textual representation of the proxy type
 * [static]
 */
const char *
NetProtectAddr::ProxyName(ProxyType t)
{
	switch( t )
	{
	case PROXY_NONE:	return "";
	case PROXY_SET:		return "proxy-";
	case PROXY_OPT:		return "*";
	}

	// quiet warning c4715: not all control paths return a value
	return "<unknown>";
}

/*
 * Debugging -- generate a textual representation of the address type
 */
const char *
NetProtectAddr::TypeName() const
{
	return TypeName(m_type);
}

/*
 * Debugging -- generate a textual representation of the proxy type
 */
const char *
NetProtectAddr::ProxyName() const
{
	return ProxyName(m_proxy);
}

/*
 * Debugging -- generate a textual representation of this object
 */
void
NetProtectAddr::ToString(StrBuf &buf) const
{
	char numbuf[64];
	const char *num = StrBuf::Itoa(m_prefixlen, &numbuf[sizeof(numbuf)-1]);
	StrBuf	nipabuf;
	m_nipa.ToString(nipabuf);

	buf.Set( "{" );
	buf.Append( ProxyName() );
	buf.Append( nipabuf.Text() );
	buf.Append( "/" );
	buf.Append( num );
	buf.Append( "%" );
	buf.Append( TypeName() );
	buf.Append( "}" );
}
# Change User Description Committed
#1 19472 Liz Lam Initial add of the 2016.1 p4/p4api source code.