@ -8,9 +8,56 @@
# include "Utilities.h"
# include <fmt/format.h>
# include <cstdint>
# include <cstdio>
# include <sstream>
# include <vector>
namespace {
constexpr auto DefaultIpAddress { " 127.0.0.1 " } ;
uint32_t ipStrToInt ( const std : : string & ip )
{
std : : stringstream ss ( ip ) ;
std : : string p ;
std : : vector < unsigned > parts ;
while ( getline ( ss , p , ' . ' ) )
parts . emplace_back ( std : : stoul ( p ) ) ;
uint32_t ret = parts [ 0 ] ;
for ( int i = 1 ; i < 4 ; + + i ) {
ret < < = 8u ;
ret | = parts [ i ] ;
}
return ret ;
}
std : : string getIpFromSecondToken ( const std : : string & input )
{
if ( input . empty ( ) )
return { } ;
/*
* Simple shell injection check , input is likely to come from a popen ( ) ( shell ) call .
* There is no way to tell if the called program has been tampered with . . .
*/
auto it = std : : find_if ( begin ( input ) , end ( input ) ,
[ ] ( char c ) {
return c = = ' | ' | | c = = ' & ' | | c = = ' ; ' | | c = = ' $ ' ;
} ) ;
if ( it ! = input . end ( ) )
return DefaultIpAddress ; // someone's fooling around with 'ip' command, let's not continue...
else {
auto start = input . find ( ' ' ) + 1 ;
auto len = input . find ( ' ' , start ) ;
if ( len ! = std : : string : : npos )
len - = start ;
return input . substr ( start , len ) ;
}
}
} // anonymous namespace
std : : pair < std : : string , std : : string > FormatCTCPLine ( std : : string line )
{
/* Clean away the CTCP byte flags */
@ -97,19 +144,7 @@ std::string longIpToNormal(const std::string& longip)
std : : string normalIpToLong ( const std : : string & normalip )
{
std : : stringstream ss ( normalip ) ;
std : : string p ;
std : : vector < unsigned > parts ;
while ( getline ( ss , p , ' . ' ) )
parts . emplace_back ( std : : stoul ( p ) ) ;
uint32_t ret = parts [ 0 ] ;
for ( int i = 1 ; i < 4 ; + + i ) {
ret < < = 8u ;
ret | = parts [ i ] ;
}
return std : : to_string ( ret ) ;
return std : : to_string ( ipStrToInt ( normalip ) ) ;
}
std : : string concatenateModes ( const std : : unordered_map < char , std : : string > & modes )
@ -193,3 +228,128 @@ std::string toBase64(const std::string& input)
return ret ;
}
std : : string findOwnIpAddress ( )
{
std : : string ipaddr { DefaultIpAddress } ;
# if defined(__linux__) || defined(__linux)
std : : string iface ;
{
char buf [ 64 ] { } ;
// This command will return either empty or something like "dev eth0 some more data here" - we want the eth0 part.
auto fd = popen ( R " (ip route show default | grep -E -o 'dev \ s.+( \ s|$)') " , " r " ) ;
auto readres = fgets ( buf , sizeof ( buf ) , fd ) ;
pclose ( fd ) ;
if ( ! readres )
return ipaddr ;
iface . assign ( buf , sizeof ( buf ) ) ;
iface = getIpFromSecondToken ( iface ) ;
}
if ( ! iface . empty ( ) ) {
char buf [ 64 ] { } ;
// This command will match either empty or exactly "inet 123.45.67.89" though with a proper IP address.
static constexpr auto regex { R " (inet \ s[[:digit:]]{1,3} \ .[[:digit:]]{1,3} \ .[[:digit:]]{1,3} \ .[[:digit:]]{1,3}) " } ;
const auto cmd { fmt : : format ( " ip address show {} | grep -E -o '{}' " , iface , regex ) } ;
auto fd = popen ( cmd . c_str ( ) , " r " ) ;
auto readres = fgets ( buf , sizeof ( buf ) - 1 , fd ) ;
pclose ( fd ) ;
if ( ! readres )
return ipaddr ;
// We use strlen() since buf will hold many zero-bytes and popen() doesn't give us a size.
ipaddr . assign ( buf , strlen ( buf ) ) ;
auto start = ipaddr . find ( ' ' ) + 1 ;
ipaddr = ipaddr . substr ( start ) ;
if ( ipaddr . back ( ) = = ' \n ' )
ipaddr . erase ( ipaddr . end ( ) - 1 ) ;
}
# elif defined(WI32) || defined(WIN64)
return " 127.0.0.1 " ; // TODO
# else
# error Unsupported platform, implementation of findOwnIpAddress() missing!
# endif
return ipaddr . empty ( ) ? DefaultIpAddress : ipaddr ;
}
std : : string findOwnGatewayIpAddress ( )
{
std : : string ipaddr { DefaultIpAddress } ;
# if defined(__linux__) || defined(__linux)
std : : string gateway ;
{
char buf [ 64 ] { } ;
// This command will return either empty or something like "via 10.0.0.1 some more data here" - we want the 10.0.0.1 part.
auto fd = popen ( R " (ip route show default | grep -E -o 'via \ s.+( \ s|$)') " , " r " ) ;
auto readres = fgets ( buf , sizeof ( buf ) , fd ) ;
pclose ( fd ) ;
if ( ! readres )
return ipaddr ;
gateway . assign ( buf , sizeof ( buf ) ) ;
ipaddr = getIpFromSecondToken ( gateway ) ;
}
# elif defined(WI32) || defined(WIN64)
return " 127.0.0.1 " ; // TODO
# else
# error Unsupported platform, implementation of findOwnIpAddress() missing!
# endif
return ipaddr . empty ( ) ? DefaultIpAddress : ipaddr ;
}
bool isPrivateIp ( const std : : string & ip )
{
/*
* Class A : 10.0 .0 .0 - 10.255 .255 .255
* Class B : 172.16 .0 .0 - 172.31 .255 .255
* Class C : 192.168 .0 .0 - 192.168 .255 .255
*/
const auto intip { ipStrToInt ( ip ) } ;
const auto classIp { ( intip & 0xFF000000 ) > > 24 } ;
/* Class A */
if ( classIp = = 10 ) {
// All addresses starting on "10." is in fact private.
return true ;
}
/* Class B */
else if ( classIp = = 172 ) {
// Check if second byte is between 16 and 31.
const auto num = ( intip & 0x00FF0000 ) > > 16 ;
return ( num > = 16 & & num < = 31 ) ;
}
/* Class C */
else if ( classIp = = 192 ) {
// Check if second byte is exactly 168.
return ( ( intip & 0x00FF0000 ) > > 16 ) = = 168 ;
}
/* Not in any of the classes, not a private IP. */
else {
return false ;
}
}