Messy starting point. But it works
This commit is contained in:
7
Makefile
7
Makefile
@ -1,9 +1,12 @@
|
|||||||
CXXFLAGS+= -std=c++23
|
CXXFLAGS+= -std=c++23
|
||||||
LDLIBS+= -lalepha
|
LDLIBS+= -lalepha
|
||||||
LDFLAGS+= -L Alepha/build-debug -Wl,-rpath,/home/user/proj/ipam/Alepha/build-debug
|
LDFLAGS+= -L Alepha/build-debug -Wl,-rpath,/home/user/proj/ipam/Alepha/build-debug
|
||||||
CPPFLAGS+= -I .
|
CPPFLAGS+= -I . -g -O0
|
||||||
|
|
||||||
all: test
|
all: test ipam
|
||||||
|
|
||||||
test: ipam
|
test: ipam
|
||||||
./ipam
|
./ipam
|
||||||
|
|
||||||
|
clean:
|
||||||
|
${RM} ipam
|
||||||
|
120
ipam.cc
120
ipam.cc
@ -7,10 +7,13 @@
|
|||||||
#include <boost/asio/ip/network_v6.hpp>
|
#include <boost/asio/ip/network_v6.hpp>
|
||||||
|
|
||||||
#include <Alepha/IOStreams/Streamable.h>
|
#include <Alepha/IOStreams/Streamable.h>
|
||||||
|
#include <Alepha/IOStreams/String.h>
|
||||||
|
|
||||||
namespace asio= boost::asio;
|
namespace asio= boost::asio;
|
||||||
namespace ip= asio::ip;
|
namespace ip= asio::ip;
|
||||||
|
|
||||||
|
using Alepha::IOStreams::Str;
|
||||||
|
|
||||||
template< typename= Alepha::Capabilities< Alepha::IOStreams::Streamable > >
|
template< typename= Alepha::Capabilities< Alepha::IOStreams::Streamable > >
|
||||||
struct Allocation_core;
|
struct Allocation_core;
|
||||||
|
|
||||||
@ -27,7 +30,13 @@ struct IP_Address : ip::network_v6
|
|||||||
{
|
{
|
||||||
std::string s;
|
std::string s;
|
||||||
is >> s;
|
is >> s;
|
||||||
|
std::cerr << "Network string: " << s << std::endl;
|
||||||
|
if( not s.contains( '/' ) )
|
||||||
|
{
|
||||||
|
throw std::runtime_error{ "No subnet mask detected. Did you forget a `/`?" };
|
||||||
|
}
|
||||||
a= ip::make_network_v6( s );
|
a= ip::make_network_v6( s );
|
||||||
|
std::cerr << "Parsed into: `" << a << std::endl;
|
||||||
|
|
||||||
return is;
|
return is;
|
||||||
}
|
}
|
||||||
@ -36,12 +45,17 @@ struct IP_Address : ip::network_v6
|
|||||||
template< typename >
|
template< typename >
|
||||||
struct Allocation_core
|
struct Allocation_core
|
||||||
{
|
{
|
||||||
ip::network_v6 network;
|
IP_Address network;
|
||||||
|
|
||||||
std::string owner;
|
std::string owner;
|
||||||
std::string name;
|
std::string name;
|
||||||
std::string purpose;
|
std::string purpose;
|
||||||
|
|
||||||
|
std::string country;
|
||||||
|
std::string region;
|
||||||
|
std::string city;
|
||||||
|
std::string postal;
|
||||||
|
|
||||||
std::vector< Allocation > subAllocations() const;
|
std::vector< Allocation > subAllocations() const;
|
||||||
std::vector< Allocation > available() const;
|
std::vector< Allocation > available() const;
|
||||||
};
|
};
|
||||||
@ -85,6 +99,10 @@ try
|
|||||||
{
|
{
|
||||||
spaces.push_back( { ip::make_network_v6( "2000::/3" ), "IANA", "Global Routing - v6", "The initial global routing table for v6" } );
|
spaces.push_back( { ip::make_network_v6( "2000::/3" ), "IANA", "Global Routing - v6", "The initial global routing table for v6" } );
|
||||||
|
|
||||||
|
spaces.push_back( { ip::make_network_v6( "2600::/8" ), "ARIN", "ARIN v6 RIR Allocation", "Large ARIN block." } );
|
||||||
|
|
||||||
|
spaces.push_back( { ip::make_network_v6( "2602:f6a8::/36" ), "IMP-NET", "Imperial Network", "Main Imperial Network Allocation." } );
|
||||||
|
|
||||||
add_command
|
add_command
|
||||||
(
|
(
|
||||||
{
|
{
|
||||||
@ -100,6 +118,18 @@ try
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
add_command
|
||||||
|
(
|
||||||
|
{
|
||||||
|
"quit",
|
||||||
|
"Exits the IP Address Manager",
|
||||||
|
[]( ... )
|
||||||
|
{
|
||||||
|
::exit( EXIT_SUCCESS );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
add_command
|
add_command
|
||||||
(
|
(
|
||||||
{
|
{
|
||||||
@ -107,22 +137,43 @@ try
|
|||||||
"Describe a network range",
|
"Describe a network range",
|
||||||
[]( const std::vector< std::string > &args )
|
[]( const std::vector< std::string > &args )
|
||||||
{
|
{
|
||||||
|
if( args.empty() ) throw std::runtime_error{ "Requires one argument." };
|
||||||
if( args.size() != 1 ) throw std::runtime_error{ "Too many arguments." };
|
if( args.size() != 1 ) throw std::runtime_error{ "Too many arguments." };
|
||||||
|
|
||||||
const auto &network= boost::lexical_cast< IP_Address >( args.at( 0 ) );
|
const auto &network= boost::lexical_cast< IP_Address >( args.at( 0 ) );
|
||||||
|
std::cout << "Parsed: `" << network << "` -- it has a " << network.prefix_length()
|
||||||
|
<< " bit mask." << std::endl;
|
||||||
|
|
||||||
const Allocation *p= nullptr;
|
const Allocation *p= nullptr;
|
||||||
|
|
||||||
|
std::optional< IP_Address > found;
|
||||||
|
auto better= [&]( const auto &where )
|
||||||
|
{
|
||||||
|
return not found.has_value() or where.is_subnet_of( found.value() );
|
||||||
|
};
|
||||||
|
|
||||||
for( const auto &space: spaces )
|
for( const auto &space: spaces )
|
||||||
{
|
{
|
||||||
const auto &[ where, owner, name, purpose ]= space;
|
const auto &[ where, owner, name, purpose, country, state, city, postal ]= space;
|
||||||
if( where == network )
|
std::cerr << "Checking " << network << " against: " << where;
|
||||||
|
if( network == where )
|
||||||
{
|
{
|
||||||
|
std::cerr << " -- Exact match!" << std::endl;
|
||||||
|
found= where;
|
||||||
p= &space;
|
p= &space;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if( network.is_subnet_of( where ) and better( where ) )
|
||||||
|
{
|
||||||
|
std::cerr << " -- Matched." << std::endl;
|
||||||
|
found= where;
|
||||||
|
p = &space;
|
||||||
}
|
}
|
||||||
const auto &[ _, owner, name, purpose ]= *p;
|
else std::cerr << " -- No match." << std::endl;
|
||||||
|
}
|
||||||
|
std::cout << network << " was best matched by " << found.value() << std::endl;
|
||||||
|
|
||||||
|
const auto &[ _, owner, name, purpose, country, state, city, postal ]= *p;
|
||||||
|
|
||||||
std::cout << network << " is owned by " << owner << std::endl;
|
std::cout << network << " is owned by " << owner << std::endl;
|
||||||
std::cout << "It is called `" << name << "`" << std::endl;
|
std::cout << "It is called `" << name << "`" << std::endl;
|
||||||
@ -131,9 +182,57 @@ try
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
add_command
|
||||||
|
(
|
||||||
|
{
|
||||||
|
"subnets",
|
||||||
|
"Describe a network range's subnets",
|
||||||
|
[]( const std::vector< std::string > &args )
|
||||||
|
{
|
||||||
|
if( args.empty() ) throw std::runtime_error{ "Requires one argument." };
|
||||||
|
if( args.size() != 1 ) throw std::runtime_error{ "Too many arguments." };
|
||||||
|
|
||||||
|
const auto &network= boost::lexical_cast< IP_Address >( args.at( 0 ) );
|
||||||
|
std::cout << "Parsed: `" << network << "` -- it has a " << network.prefix_length()
|
||||||
|
<< " bit mask." << std::endl;
|
||||||
|
|
||||||
|
const Allocation *p= nullptr;
|
||||||
|
|
||||||
|
std::optional< IP_Address > found;
|
||||||
|
auto better= [&]( const auto &where )
|
||||||
|
{
|
||||||
|
return not found.has_value() or where.is_subnet_of( found.value() );
|
||||||
|
};
|
||||||
|
|
||||||
|
for( const auto &space: spaces )
|
||||||
|
{
|
||||||
|
const auto &[ where, owner, name, purpose, country, state, city, postal ]= space;
|
||||||
|
if( network.is_subnet_of( where ) and better( where ) )
|
||||||
|
{
|
||||||
|
found= where;
|
||||||
|
p = &space;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::cout << network << " was best matched by " << found.value() << std::endl;
|
||||||
|
|
||||||
|
const auto &[ _, owner, name, purpose, country, state, city, postal ]= *p;
|
||||||
|
|
||||||
|
std::cout << network << " is owned by " << owner << std::endl;
|
||||||
|
std::cout << "It is called `" << name << "`" << std::endl;
|
||||||
|
std::cout << "It is used for '" << purpose << "'" << std::endl;
|
||||||
|
|
||||||
|
for( const auto &sub: p->subAllocations() )
|
||||||
|
{
|
||||||
|
std::cout << sub.network << ": " << owner << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
while( true )
|
|
||||||
|
while( not std::cin.eof() )
|
||||||
|
try
|
||||||
{
|
{
|
||||||
std::string line;
|
std::string line;
|
||||||
getline( std::cin, line );
|
getline( std::cin, line );
|
||||||
@ -143,13 +242,22 @@ try
|
|||||||
auto args= parsed;
|
auto args= parsed;
|
||||||
args.erase( begin( args ) );
|
args.erase( begin( args ) );
|
||||||
|
|
||||||
|
if( command.empty() ) continue;
|
||||||
|
if( not commands.contains( command ) )
|
||||||
|
{
|
||||||
|
throw std::runtime_error{ Str << "No such command `" << command << '`' };
|
||||||
|
}
|
||||||
commands.at( command ).run( args );
|
commands.at( command ).run( args );
|
||||||
}
|
}
|
||||||
|
catch( const std::exception &e )
|
||||||
|
{
|
||||||
|
std::cerr << "ERROR: " << e.what() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
catch( const std::exception &ex )
|
catch( const std::exception &ex )
|
||||||
{
|
{
|
||||||
std::cerr << "Error: " << ex.what() << std::endl;
|
std::cerr << "FATAL ERROR: " << ex.what() << std::endl;
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user