@ -1,72 +1,18 @@
/*
* owipcalc - OpenWrt IP Calculator
*
* Copyright ( C ) 2012 Jo - Philipp Wich < jo @ mein . io >
*
* Licensed under the Apache License , Version 2.0 ( the " License " ) ;
* you may not use this file except in compliance with the License .
* You may obtain a copy of the License at
*
* http : / / www . apache . org / licenses / LICENSE - 2.0
*
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an " AS IS " BASIS ,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* See the License for the specific language governing permissions and
* limitations under the License .
*/
# include <stdio.h>
# include <stdint.h>
# include <stdbool.h>
# include <stdlib.h>
# include <string.h>
# include <unistd.h>
# include <arpa/inet.h>
# include "owipcalc.h"
bool quiet = true ;
bool printed = false ;
struct cidr * stack = NULL ;
struct cidr {
uint8_t family ;
uint32_t prefix ;
union {
struct in_addr v4 ;
struct in6_addr v6 ;
} addr ;
union {
char v4 [ sizeof ( " 255.255.255.255/255.255.255.255 " ) ] ;
char v6 [ sizeof ( " FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:255.255.255.255/128 " ) ] ;
} buf ;
struct cidr * next ;
} ;
struct op {
const char * name ;
const char * desc ;
struct {
bool ( * a1 ) ( struct cidr * a ) ;
bool ( * a2 ) ( struct cidr * a , struct cidr * b ) ;
} f4 ;
struct {
bool ( * a1 ) ( struct cidr * a ) ;
bool ( * a2 ) ( struct cidr * a , struct cidr * b ) ;
} f6 ;
} ;
static bool quiet = false ;
static bool printed = false ;
static struct cidr * stack = NULL ;
# define qprintf(...) \
do { \
if ( ! quiet ) printf ( __VA_ARGS__ ) ; \
printed = true ; \
} while ( 0 )
static void cidr_push ( struct cidr * a )
void cidr_push ( struct cidr * a )
{
if ( a )
{
@ -75,7 +21,7 @@ static void cidr_push(struct cidr *a)
}
}
static bool cidr_pop ( struct cidr * a )
bool cidr_pop ( struct cidr * a )
{
struct cidr * old = stack ;
@ -107,7 +53,7 @@ static struct cidr * cidr_clone(struct cidr *a)
}
static struct cidr * cidr_parse4 ( const char * s )
struct cidr * cidr_parse4 ( const char * s )
{
char * p = NULL , * r ;
struct in_addr mask ;
@ -159,7 +105,7 @@ err:
return NULL ;
}
static bool cidr_add4 ( struct cidr * a , struct cidr * b )
bool cidr_add4 ( struct cidr * a , struct cidr * b )
{
uint32_t x = ntohl ( a - > addr . v4 . s_addr ) ;
uint32_t y = ntohl ( b - > addr . v4 . s_addr ) ;
@ -179,7 +125,7 @@ static bool cidr_add4(struct cidr *a, struct cidr *b)
return true ;
}
static bool cidr_sub4 ( struct cidr * a , struct cidr * b )
bool cidr_sub4 ( struct cidr * a , struct cidr * b )
{
uint32_t x = ntohl ( a - > addr . v4 . s_addr ) ;
uint32_t y = ntohl ( b - > addr . v4 . s_addr ) ;
@ -199,7 +145,7 @@ static bool cidr_sub4(struct cidr *a, struct cidr *b)
return true ;
}
static bool cidr_network4 ( struct cidr * a )
bool cidr_network4 ( struct cidr * a )
{
struct cidr * n = cidr_clone ( a ) ;
@ -209,7 +155,7 @@ static bool cidr_network4(struct cidr *a)
return true ;
}
static bool cidr_broadcast4 ( struct cidr * a )
bool cidr_broadcast4 ( struct cidr * a )
{
struct cidr * n = cidr_clone ( a ) ;
@ -219,7 +165,7 @@ static bool cidr_broadcast4(struct cidr *a)
return true ;
}
static bool cidr_contains4 ( struct cidr * a , struct cidr * b )
bool cidr_contains4 ( struct cidr * a , struct cidr * b )
{
uint32_t net1 = a - > addr . v4 . s_addr & htonl ( ~ ( ( 1 < < ( 32 - a - > prefix ) ) - 1 ) ) ;
uint32_t net2 = b - > addr . v4 . s_addr & htonl ( ~ ( ( 1 < < ( 32 - a - > prefix ) ) - 1 ) ) ;
@ -239,7 +185,7 @@ static bool cidr_contains4(struct cidr *a, struct cidr *b)
}
}
static bool cidr_netmask4 ( struct cidr * a )
bool cidr_netmask4 ( struct cidr * a )
{
struct cidr * n = cidr_clone ( a ) ;
@ -249,7 +195,7 @@ static bool cidr_netmask4(struct cidr *a)
return true ;
}
static bool cidr_private4 ( struct cidr * a )
bool cidr_private4 ( struct cidr * a )
{
uint32_t x = ntohl ( a - > addr . v4 . s_addr ) ;
@ -270,7 +216,7 @@ static bool cidr_private4(struct cidr *a)
}
}
static bool cidr_linklocal4 ( struct cidr * a )
bool cidr_linklocal4 ( struct cidr * a )
{
uint32_t x = ntohl ( a - > addr . v4 . s_addr ) ;
@ -289,7 +235,7 @@ static bool cidr_linklocal4(struct cidr *a)
}
}
static bool cidr_prev4 ( struct cidr * a , struct cidr * b )
bool cidr_prev4 ( struct cidr * a , struct cidr * b )
{
struct cidr * n = cidr_clone ( a ) ;
@ -299,7 +245,7 @@ static bool cidr_prev4(struct cidr *a, struct cidr *b)
return true ;
}
static bool cidr_next4 ( struct cidr * a , struct cidr * b )
bool cidr_next4 ( struct cidr * a , struct cidr * b )
{
struct cidr * n = cidr_clone ( a ) ;
@ -309,7 +255,7 @@ static bool cidr_next4(struct cidr *a, struct cidr *b)
return true ;
}
static bool cidr_6to4 ( struct cidr * a )
bool cidr_6to4 ( struct cidr * a )
{
struct cidr * n = cidr_clone ( a ) ;
uint32_t x = a - > addr . v4 . s_addr ;
@ -329,7 +275,7 @@ static bool cidr_6to4(struct cidr *a)
return true ;
}
static bool cidr_print4 ( struct cidr * a )
bool cidr_print4 ( struct cidr * a )
{
char * p ;
@ -353,7 +299,7 @@ static bool cidr_print4(struct cidr *a)
}
static struct cidr * cidr_parse6 ( const char * s )
struct cidr * cidr_parse6 ( const char * s )
{
char * p = NULL , * r ;
struct cidr * addr = malloc ( sizeof ( struct cidr ) ) ;
@ -393,7 +339,7 @@ err:
return NULL ;
}
static bool cidr_add6 ( struct cidr * a , struct cidr * b )
bool cidr_add6 ( struct cidr * a , struct cidr * b )
{
uint8_t idx = 15 , carry = 0 , overflow = 0 ;
@ -420,7 +366,7 @@ static bool cidr_add6(struct cidr *a, struct cidr *b)
return true ;
}
static bool cidr_sub6 ( struct cidr * a , struct cidr * b )
bool cidr_sub6 ( struct cidr * a , struct cidr * b )
{
uint8_t idx = 15 , carry = 0 , underflow = 0 ;
@ -447,7 +393,7 @@ static bool cidr_sub6(struct cidr *a, struct cidr *b)
return true ;
}
static bool cidr_prev6 ( struct cidr * a , struct cidr * b )
bool cidr_prev6 ( struct cidr * a , struct cidr * b )
{
uint8_t idx , carry = 1 , underflow = 0 ;
struct cidr * n = cidr_clone ( a ) ;
@ -479,7 +425,7 @@ static bool cidr_prev6(struct cidr *a, struct cidr *b)
return true ;
}
static bool cidr_next6 ( struct cidr * a , struct cidr * b )
bool cidr_next6 ( struct cidr * a , struct cidr * b )
{
uint8_t idx , carry = 1 , overflow = 0 ;
struct cidr * n = cidr_clone ( a ) ;
@ -511,7 +457,7 @@ static bool cidr_next6(struct cidr *a, struct cidr *b)
return true ;
}
static bool cidr_network6 ( struct cidr * a )
bool cidr_network6 ( struct cidr * a )
{
uint8_t i ;
struct cidr * n = cidr_clone ( a ) ;
@ -525,7 +471,7 @@ static bool cidr_network6(struct cidr *a)
return true ;
}
static bool cidr_contains6 ( struct cidr * a , struct cidr * b )
bool cidr_contains6 ( struct cidr * a , struct cidr * b )
{
struct in6_addr * x = & a - > addr . v6 ;
struct in6_addr * y = & b - > addr . v6 ;
@ -551,7 +497,7 @@ static bool cidr_contains6(struct cidr *a, struct cidr *b)
}
}
static bool cidr_linklocal6 ( struct cidr * a )
bool cidr_linklocal6 ( struct cidr * a )
{
if ( printed )
qprintf ( " " ) ;
@ -570,7 +516,7 @@ static bool cidr_linklocal6(struct cidr *a)
}
}
static bool cidr_ula6 ( struct cidr * a )
bool cidr_ula6 ( struct cidr * a )
{
if ( printed )
qprintf ( " " ) ;
@ -588,7 +534,7 @@ static bool cidr_ula6(struct cidr *a)
}
}
static bool cidr_print6 ( struct cidr * a )
bool cidr_print6 ( struct cidr * a )
{
char * p ;
@ -612,7 +558,7 @@ static bool cidr_print6(struct cidr *a)
}
static struct cidr * cidr_parse ( const char * op , const char * s , int af_hint )
struct cidr * cidr_parse ( const char * op , const char * s , int af_hint )
{
char * r ;
struct cidr * a ;
@ -668,7 +614,7 @@ static struct cidr * cidr_parse(const char *op, const char *s, int af_hint)
return a ;
}
static bool cidr_howmany ( struct cidr * a , struct cidr * b )
bool cidr_howmany ( struct cidr * a , struct cidr * b )
{
if ( printed )
qprintf ( " " ) ;
@ -681,271 +627,14 @@ static bool cidr_howmany(struct cidr *a, struct cidr *b)
return true ;
}
static bool cidr_prefix ( struct cidr * a , struct cidr * b )
bool cidr_prefix ( struct cidr * a , struct cidr * b )
{
a - > prefix = b - > prefix ;
return true ;
}
static bool cidr_quiet ( struct cidr * a )
bool cidr_quiet ( struct cidr * a )
{
quiet = true ;
return true ;
}
struct op ops [ ] = {
{ . name = " add " ,
. desc = " Add argument to base address " ,
. f4 . a2 = cidr_add4 ,
. f6 . a2 = cidr_add6 } ,
{ . name = " sub " ,
. desc = " Substract argument from base address " ,
. f4 . a2 = cidr_sub4 ,
. f6 . a2 = cidr_sub6 } ,
{ . name = " next " ,
. desc = " Advance base address to next prefix of given size " ,
. f4 . a2 = cidr_next4 ,
. f6 . a2 = cidr_next6 } ,
{ . name = " prev " ,
. desc = " Lower base address to previous prefix of give size " ,
. f4 . a2 = cidr_prev4 ,
. f6 . a2 = cidr_prev6 } ,
{ . name = " network " ,
. desc = " Turn base address into network address " ,
. f4 . a1 = cidr_network4 ,
. f6 . a1 = cidr_network6 } ,
{ . name = " broadcast " ,
. desc = " Turn base address into broadcast address " ,
. f4 . a1 = cidr_broadcast4 } ,
{ . name = " prefix " ,
. desc = " Set the prefix of base address to argument " ,
. f4 . a2 = cidr_prefix ,
. f6 . a2 = cidr_prefix } ,
{ . name = " netmask " ,
. desc = " Calculate netmask of base address " ,
. f4 . a1 = cidr_netmask4 } ,
{ . name = " 6to4 " ,
. desc = " Calculate 6to4 prefix of given ipv4-address " ,
. f4 . a1 = cidr_6to4 } ,
{ . name = " howmany " ,
. desc = " Print amount of righ-hand prefixes that fit into base address " ,
. f4 . a2 = cidr_howmany ,
. f6 . a2 = cidr_howmany } ,
{ . name = " contains " ,
. desc = " Print '1' if argument fits into base address or '0' if not " ,
. f4 . a2 = cidr_contains4 ,
. f6 . a2 = cidr_contains6 } ,
{ . name = " private " ,
. desc = " Print '1' if base address is in RFC1918 private space or '0' "
" if not " ,
. f4 . a1 = cidr_private4 } ,
{ . name = " linklocal " ,
. desc = " Print '1' if base address is in 169.254.0.0/16 or FE80::/10 "
" link local space or '0' if not " ,
. f4 . a1 = cidr_linklocal4 ,
. f6 . a1 = cidr_linklocal6 } ,
{ . name = " ula " ,
. desc = " Print '1' if base address is in FC00::/7 unique local address "
" (ULA) space or '0' if not " ,
. f6 . a1 = cidr_ula6 } ,
{ . name = " quiet " ,
. desc = " Suppress output, useful for test operation where the result can "
" be inferred from the exit code " ,
. f4 . a1 = cidr_quiet ,
. f6 . a1 = cidr_quiet } ,
{ . name = " pop " ,
. desc = " Pop intermediate result from stack " ,
. f4 . a1 = cidr_pop ,
. f6 . a1 = cidr_pop } ,
{ . name = " print " ,
. desc = " Print intermediate result and pop it from stack, invoked "
" implicitely at the end of calculation if no intermediate prints "
" happened " ,
. f4 . a1 = cidr_print4 ,
. f6 . a1 = cidr_print6 } ,
} ;
static void usage ( const char * prog )
{
int i ;
fprintf ( stderr ,
" \n "
" Usage: \n \n "
" %s {base address} operation [argument] "
" [operation [argument] ...] \n \n "
" Operations: \n \n " ,
prog ) ;
for ( i = 0 ; i < sizeof ( ops ) / sizeof ( ops [ 0 ] ) ; i + + )
{
if ( ops [ i ] . f4 . a2 | | ops [ i ] . f6 . a2 )
{
fprintf ( stderr , " %s %s \n " ,
ops [ i ] . name ,
( ops [ i ] . f4 . a2 & & ops [ i ] . f6 . a2 ) ? " {ipv4/ipv6/amount} " :
( ops [ i ] . f6 . a2 ? " {ipv6/amount} " : " {ipv4/amount} " ) ) ;
}
else
{
fprintf ( stderr , " %s \n " , ops [ i ] . name ) ;
}
fprintf ( stderr , " %s. \n " , ops [ i ] . desc ) ;
if ( ( ops [ i ] . f4 . a1 & & ops [ i ] . f6 . a1 ) | | ( ops [ i ] . f4 . a2 & & ops [ i ] . f6 . a2 ) )
fprintf ( stderr , " Applicable to ipv4- and ipv6-addresses. \n \n " ) ;
else if ( ops [ i ] . f6 . a2 | | ops [ i ] . f6 . a1 )
fprintf ( stderr , " Only applicable to ipv6-addresses. \n \n " ) ;
else
fprintf ( stderr , " Only applicable to ipv4-addresses. \n \n " ) ;
}
fprintf ( stderr ,
" Examples: \n \n "
" Calculate a DHCP range: \n \n "
" $ %s 192.168.1.1/255.255.255.0 network add 100 print add 150 print \n "
" 192.168.1.100 \n "
" 192.168.1.250 \n \n "
" Count number of prefixes: \n \n "
" $ %s 2001:0DB8:FDEF::/48 howmany ::/64 \n "
" 65536 \n \n " ,
prog , prog ) ;
exit ( 1 ) ;
}
static bool runop ( char * * * arg , int * status )
{
int i ;
char * arg1 = * * arg ;
char * arg2 = * ( * arg + 1 ) ;
struct cidr * a = stack ;
struct cidr * b = NULL ;
if ( ! arg1 )
return false ;
for ( i = 0 ; i < sizeof ( ops ) / sizeof ( ops [ 0 ] ) ; i + + )
{
if ( ! strcmp ( ops [ i ] . name , arg1 ) )
{
if ( ops [ i ] . f4 . a2 | | ops [ i ] . f6 . a2 )
{
if ( ! arg2 )
{
fprintf ( stderr , " '%s' requires an argument \n " ,
ops [ i ] . name ) ;
* status = 2 ;
return false ;
}
b = cidr_parse ( ops [ i ] . name , arg2 , a - > family ) ;
if ( ! b )
{
fprintf ( stderr , " invalid address argument for '%s' \n " ,
ops [ i ] . name ) ;
* status = 3 ;
return false ;
}
* arg + = 2 ;
if ( ( ( a - > family = = AF_INET ) & & ! ops [ i ] . f4 . a2 ) | |
( ( a - > family = = AF_INET6 ) & & ! ops [ i ] . f6 . a2 ) )
{
fprintf ( stderr , " '%s' not supported for %s addresses \n " ,
ops [ i ] . name ,
( a - > family = = AF_INET ) ? " ipv4 " : " ipv6 " ) ;
* status = 5 ;
return false ;
}
* status = ! ( ( a - > family = = AF_INET ) ? ops [ i ] . f4 . a2 ( a , b )
: ops [ i ] . f6 . a2 ( a , b ) ) ;
return true ;
}
else
{
* arg + = 1 ;
if ( ( ( a - > family = = AF_INET ) & & ! ops [ i ] . f4 . a1 ) | |
( ( a - > family = = AF_INET6 ) & & ! ops [ i ] . f6 . a1 ) )
{
fprintf ( stderr , " '%s' not supported for %s addresses \n " ,
ops [ i ] . name ,
( a - > family = = AF_INET ) ? " ipv4 " : " ipv6 " ) ;
* status = 5 ;
return false ;
}
* status = ! ( ( a - > family = = AF_INET ) ? ops [ i ] . f4 . a1 ( a )
: ops [ i ] . f6 . a1 ( a ) ) ;
return true ;
}
}
}
return false ;
}
int main ( int argc , char * * argv )
{
int status = 0 ;
char * * arg = argv + 2 ;
struct cidr * a ;
if ( argc < 3 )
usage ( argv [ 0 ] ) ;
a = strchr ( argv [ 1 ] , ' : ' ) ? cidr_parse6 ( argv [ 1 ] ) : cidr_parse4 ( argv [ 1 ] ) ;
if ( ! a )
usage ( argv [ 0 ] ) ;
cidr_push ( a ) ;
while ( runop ( & arg , & status ) ) ;
if ( * arg )
{
fprintf ( stderr , " unknown operation '%s' \n " , * arg ) ;
exit ( 6 ) ;
}
if ( ! printed & & ( status < 2 ) )
{
if ( stack - > family = = AF_INET )
cidr_print4 ( stack ) ;
else
cidr_print6 ( stack ) ;
}
qprintf ( " \n " ) ;
exit ( status ) ;
}