From 13a6e69f4e4fd98637d84e78df290a920c0605d6 Mon Sep 17 00:00:00 2001 From: Michael Tremer Date: Fri, 18 Sep 2015 22:37:05 +0200 Subject: [PATCH] Replace ipcalc by inetcalc This is our own implementation of a binary tool that is used to validate and calculate with IP addresses. Signed-off-by: Michael Tremer Reviewed-by: Stefan Schantl --- .gitignore | 4 + Makefile.am | 6 + src/dhclient-script | 2 +- src/functions/functions.device | 2 +- src/functions/functions.dhcpd | 2 +- src/functions/functions.ip | 28 +- src/functions/functions.ip-tunnel | 2 +- src/functions/functions.ipv4 | 221 ++++++------ src/functions/functions.ipv6 | 122 ++----- src/functions/functions.radvd | 4 +- src/functions/functions.routing | 4 +- src/hooks/configs/ipv6-static | 6 +- src/hooks/zones/6rd | 2 +- src/inetcalc.c | 548 ++++++++++++++++++++++++++++++ 14 files changed, 737 insertions(+), 216 deletions(-) create mode 100644 src/inetcalc.c diff --git a/.gitignore b/.gitignore index d522de39..ad5e18f0 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ /build-aux /missing /src/functions/functions +/src/inetcalc /src/network.pc /src/ppp/ip-updown /src/systemd/*.service @@ -11,9 +12,12 @@ /*.tar.xz *.log *.cache +*.o *.stamp *.trs *~ +.deps +.dirstamp Makefile.in aclocal.m4 config.status diff --git a/Makefile.am b/Makefile.am index 7c780ac1..bd81906a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -177,6 +177,12 @@ dist_helpers_SCRIPTS = \ src/helpers/wpa_supplicant \ src/helpers/wpa_supplicant-config-helper +bin_PROGRAMS = \ + src/inetcalc + +src_inetcalc_SOURCES = \ + src/inetcalc.c + bridge-stp-install-hook: bridge-stp-uninstall-hook ln -svf --relative $(DESTDIR)$(helpersdir)/bridge-stp $(DESTDIR)$(sbindir)/ diff --git a/src/dhclient-script b/src/dhclient-script index 9d18dba2..73dfbfaa 100644 --- a/src/dhclient-script +++ b/src/dhclient-script @@ -218,7 +218,7 @@ case "${reason}" in # Calc a prefix out of address and subnet mask. - new_prefix="$(ipv4_get_prefix ${new_ip_address} ${new_subnet_mask})" + new_prefix="$(ipv4_calculate_prefix ${new_ip_address} ${new_subnet_mask})" # Set the new ip address. ip_address_add ${interface} ${new_ip_address}/${new_prefix} diff --git a/src/functions/functions.device b/src/functions/functions.device index d5ff381d..a851b669 100644 --- a/src/functions/functions.device +++ b/src/functions/functions.device @@ -705,7 +705,7 @@ device_has_ip() { local protocol=$(ip_detect_protocol ${addr}) case "${protocol}" in ipv6) - addr=$(ipv6_implode ${addr}) + addr=$(ipv6_format "${addr}") ;; esac diff --git a/src/functions/functions.dhcpd b/src/functions/functions.dhcpd index b1f87674..823fca47 100644 --- a/src/functions/functions.dhcpd +++ b/src/functions/functions.dhcpd @@ -1029,7 +1029,7 @@ _dhcpd_write_subnet() { print "subnet6 ${ADDRESS}/${PREFIX} {" >> ${file} ;; ipv4) - local netmask=$(ipv4_get_netmask ${ADDRESS}/${PREFIX}) + local netmask="$(ipv4_prefix2netmask "${PREFIX}")" print "subnet ${ADDRESS} netmask ${netmask} {" >> ${file} ;; esac diff --git a/src/functions/functions.ip b/src/functions/functions.ip index 208488ff..9572141b 100644 --- a/src/functions/functions.ip +++ b/src/functions/functions.ip @@ -40,13 +40,13 @@ ip_get_prefix() { } ip_detect_protocol() { - local address=${1} + local address="${1}" assert isset address local protocol for protocol in ${IP_SUPPORTED_PROTOCOLS}; do - if ${protocol}_is_valid ${address}; then + if ${protocol}_is_valid "${address}"; then echo "${protocol}" return ${EXIT_OK} fi @@ -113,6 +113,10 @@ ip_prefix_is_valid() { assert ip_protocol_is_supported ${proto} } +ip_get_network() { + inetcalc -n $@ && return ${EXIT_OK} || return ${EXIT_ERROR} +} + ip_address_add() { local device=${1} local address=${2} @@ -124,10 +128,22 @@ ip_address_add() { address=$(ip_split_prefix ${address}) assert isset prefix + assert isset address + + echo "ADDRESS = $address" # Detect the protocol version - local protocol=$(ip_detect_protocol ${address}/${prefix}) - assert ip_protocol_is_supported ${protocol} + local protocol=$(ip_detect_protocol "${address}") + assert ip_protocol_is_supported "${protocol}" + + case "${protocol}" in + ipv6) + assert ipv6_prefix_is_valid "${prefix}" + ;; + ipv4) + assert ipv4_prefix_is_valid "${prefix}" + ;; + esac case "${protocol}" in ipv4) @@ -170,8 +186,8 @@ ip_address_del() { assert isset prefix # Detect the protocol version - local protocol=$(ip_detect_protocol ${address}/${prefix}) - assert ip_protocol_is_supported ${protocol} + local protocol=$(ip_detect_protocol "${address}") + assert ip_protocol_is_supported "${protocol}" if device_has_ip ${device} ${address}/${prefix}; then assert ip addr del ${address}/${prefix} dev ${device} diff --git a/src/functions/functions.ip-tunnel b/src/functions/functions.ip-tunnel index 36881f28..8a1e2ee4 100644 --- a/src/functions/functions.ip-tunnel +++ b/src/functions/functions.ip-tunnel @@ -99,7 +99,7 @@ ip_tunnel_6rd_set_prefix() { assert isset prefix # Validate the prefix. - assert ipv6_is_valid "${prefix}" + assert ipv6_net_is_valid "${prefix}" log INFO "Setting 6rd-prefix ${prefix} on ${device}" diff --git a/src/functions/functions.ipv4 b/src/functions/functions.ipv4 index d22b25f6..799fe009 100644 --- a/src/functions/functions.ipv4 +++ b/src/functions/functions.ipv4 @@ -22,16 +22,7 @@ IP_SUPPORTED_PROTOCOLS="${IP_SUPPORTED_PROTOCOLS} ipv4" ipv4_is_valid() { - ipcalc --ipv4 -c $@ >/dev/null 2>&1 - - case "$?" in - 0) - return ${EXIT_OK} - ;; - *) - return ${EXIT_ERROR} - ;; - esac + inetcalc -4 -c $@ && return ${EXIT_OK} || return ${EXIT_ERROR} } ipv4_prefix_is_valid() { @@ -84,56 +75,13 @@ ipv4_update_neighbours() { ( sleep 2; arping -q -U -c 1 -I ${device} ${address} ) >/dev/null 2>&1 /dev/null 2>&1 - - case "$?" in - 0) - return ${EXIT_OK} - ;; - *) - return ${EXIT_ERROR} - ;; - esac + inetcalc -6 -c $@ && return ${EXIT_OK} || return ${EXIT_ERROR} +} + +ipv6_net_is_valid() { + local net="${1}" + + local prefix="$(ip_get_prefix "${net}")" + local addr="$(ip_split_prefix "${net}")" + + ipv6_prefix_is_valid "${prefix}" && ipv6_is_valid "${addr}" } ipv6_prefix_is_valid() { @@ -394,105 +394,45 @@ ipv6_device_get_addresses() { list_sort ${addresses} } -ipv6_implode() { - local address=${1} - assert isset address - - local ADDRESS6_IMPL - eval $(ipcalc -6 -i ${address} 2>/dev/null) - assert isset ADDRESS6_IMPL - - print "${ADDRESS6_IMPL}" -} - -ipv6_explode() { - local address=${1} - assert isset address - - # Nothing to do if the length of the address is 39. - if [ ${#address} -eq 39 ]; then - print "${address}" - return ${EXIT_OK} - fi - - local ADDRESS6_EXPL - eval $(ipcalc -6 -e ${address} 2>/dev/null) - assert isset ADDRESS6_EXPL - - print "${ADDRESS6_EXPL}" +ipv6_format() { + inetcalc -6 -f $@ } ipv6_addr_eq() { - local addr1=${1} - assert isset addr1 + assert [[ $# -eq 2 ]] - local addr2=${2} - assert isset addr2 - - local addr - for addr in addr1 addr2; do - printf -v ${addr} "%s" $(ipv6_explode ${!addr}) - done + local addr1="${1}" + local addr2="${2}" - [[ "${addr1}" = "${addr2}" ]] \ + inetcalc -6 -e "${addr1}" "${addr2}" \ && return ${EXIT_TRUE} || return ${EXIT_FALSE} } ipv6_addr_gt() { - local addr1=${1} - assert isset addr1 + assert [[ $# -eq 2 ]] - local addr2=${2} - assert isset addr2 + local addr1="${1}" + local addr2="${2}" - local addr - for addr in addr1 addr2; do - printf -v ${addr} "%s" $(ipv6_explode ${!addr}) - - # Remove all colons - printf -v ${addr} "${!addr//:/}" - done - - local i addr1_oct addr2_oct - for i in 0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30; do - addr1_oct="0x${addr1:${i}:2}" - addr2_oct="0x${addr2:${i}:2}" - - [[ ${addr1_oct} -gt ${addr2_oct} ]] && return ${EXIT_TRUE} - done - - return ${EXIT_FALSE} + inetcalc -6 -g "${addr1}" "${addr2}" \ + && return ${EXIT_TRUE} || return ${EXIT_FALSE} } ipv6_hash() { - local address=${1} - + local address="${1}" assert isset address - # Explode address - address=$(ipv6_explode ${address}) - + address="$(ipv6_format "${address}")" echo "${address//:/}" } ipv6_get_network() { - local addr=${1} - assert isset addr - - # Check if a prefix (e.g. /64) is provided. - local prefix=$(ip_get_prefix ${addr}) - assert ipv6_prefix_is_valid ${prefix} - - local PREFIX6 - eval $(ipcalc --ipv6 -p ${addr}) - assert isset PREFIX6 - - print "${PREFIX6}/${prefix}" + ip_get_network $@ } ipv6_6rd_format_address() { local isp_prefix="${1}" - assert ipv6_is_valid "${isp_prefix}" + assert ipv6_net_is_valid "${isp_prefix}" local client_address="${2}" assert ipv4_is_valid "${client_address}" @@ -505,7 +445,15 @@ ipv6_6rd_format_address() { assert [ "${prefix}" -gt 0 ] # Explode the address and throw away the second 32 bit. - local address="$(ipv6_explode "${isp_prefix}")" + local address + local segment + for segment in ${isp_prefix//:/ }; do + while [[ ${#segment} -lt 4 ]]; do + segment="0${segment}" + done + list_append address "${segment}" + done + address="$(list_join ":" ${address})" client_address="$(ipv6_6rd_format_client_address ${client_address})" assert isset client_address @@ -551,7 +499,7 @@ ipv6_6rd_format_address() { assert ipv6_is_valid "${formatted_address}" # Implode the output IP address. - formatted_address="$(ipv6_implode "${formatted_address}")" + formatted_address="$(ipv6_format "${formatted_address}")" print "${formatted_address}/${prefix}" } diff --git a/src/functions/functions.radvd b/src/functions/functions.radvd index 2079554a..a2daec35 100644 --- a/src/functions/functions.radvd +++ b/src/functions/functions.radvd @@ -69,11 +69,11 @@ __radvd_config_interface() { if [ -z "${addr}" ] || [ "${addr:0:5}" = "fe80:" ]; then return ${EXIT_OK} fi - local prefix=$(ipv6_get_network ${addr}) # Check if the subnet is configured by the DHCP server. local dhcpd="false" - if dhcpd_subnet_match ipv6 "${prefix}"; then + local prefix="$(ipv6_get_network "${addr}")" + if isset prefix && dhcpd_subnet_match ipv6 "${prefix}"; then dhcpd="true" fi diff --git a/src/functions/functions.routing b/src/functions/functions.routing index b7b0cc97..c7aac094 100644 --- a/src/functions/functions.routing +++ b/src/functions/functions.routing @@ -164,10 +164,10 @@ routing_update() { case "${proto}" in ipv4) - local net_address=$(ipv4_get_netaddress ${local_ip_address}) + local network=$(ipv4_get_network "${local_ip_address}") log DEBUG "Adding route for subnet ${local_ip_address} to table ${table}" - cmd ${ip_cmd} route add table ${table} ${net_address} dev ${zone} + cmd ${ip_cmd} route add table "${table}" "${network}" dev "${zone}" ;; esac diff --git a/src/hooks/configs/ipv6-static b/src/hooks/configs/ipv6-static index f0d07e4a..2a5e8e2c 100644 --- a/src/hooks/configs/ipv6-static +++ b/src/hooks/configs/ipv6-static @@ -53,10 +53,10 @@ hook_new() { done # Store IPv6 address in small format. - ADDRESS=$(ipv6_implode ${ADDRESS}) + ADDRESS=$(ipv6_format "${ADDRESS}") if [ -n "${GATEWAY}" ]; then - GATEWAY=$(ipv6_implode ${GATEWAY}) + GATEWAY=$(ipv6_format "${GATEWAY}") fi zone_config_settings_write "${zone}" "${HOOK}.$(ipv6_hash ${ADDRESS}).${PREFIX}" @@ -123,7 +123,7 @@ hook_status() { zone_config_settings_read "${zone}" "${config}" # Make sure ADDRESS is as short as possible. - ADDRESS=$(ipv6_implode ${ADDRESS}) + ADDRESS=$(ipv6_format "${ADDRESS}") local status if zone_has_ip ${zone} ${ADDRESS}/${PREFIX}; then diff --git a/src/hooks/zones/6rd b/src/hooks/zones/6rd index c8509f3a..a277674c 100644 --- a/src/hooks/zones/6rd +++ b/src/hooks/zones/6rd @@ -49,7 +49,7 @@ hook_check_settings() { assert isset LOCAL_ADDRESS # Check input. - if ! ipv6_is_valid "${SIX_RD_PREFIX}"; then + if ! ipv6_net_is_valid "${SIX_RD_PREFIX}"; then log ERROR "Invalid 6rd prefix. Please use a valid IPv6 prefix." return ${EXIT_ERROR} fi diff --git a/src/inetcalc.c b/src/inetcalc.c new file mode 100644 index 00000000..f821d6ed --- /dev/null +++ b/src/inetcalc.c @@ -0,0 +1,548 @@ +/*############################################################################# +# # +# IPFire.org - A linux based firewall # +# Copyright (C) 2015 IPFire Network Development Team # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +#############################################################################*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct ip_address { + int family; + __uint128_t addr; + int prefix; +} ip_address_t; + +static __uint128_t prefix_to_bitmask(int prefix) { + __uint128_t bitmask = ~0; + + for (int i = 0; i < 128 - prefix; i++) + bitmask >>= 1; + + return bitmask; +} + +static int bitmask_to_prefix(uint32_t bits) { + int prefix = 0; + + // Count all ones until we find the first zero + while (bits & (1 << 31)) { + bits <<= 1; + prefix++; + } + + // The remaining bits must all be zero + if (bits) + return -1; + + return prefix; +} + +static int ip_address_parse_subnet_mask(ip_address_t* ip, const char* prefix) { + struct in_addr mask; + + int r = inet_pton(AF_INET, prefix, &mask.s_addr); + if (r != 1) + return 1; + + uint32_t bits = ntohl(mask.s_addr); + ip->prefix = bitmask_to_prefix(bits); + + return (ip->prefix < 0 || ip->prefix > 32); +} + +static int ip_address_parse_prefix_cidr(ip_address_t* ip, const int family, const char* prefix) { + ip->prefix = 0; + while (*prefix) { + char p = *prefix++; + + if (p >= '0' && p <= '9') { + ip->prefix *= 10; + ip->prefix += p - '0'; + } else { + return 1; + } + } + + switch (family) { + case AF_INET6: + return (ip->prefix < 0 || ip->prefix > 128); + + case AF_INET: + return (ip->prefix < 0 || ip->prefix > 32); + + default: + return 1; + } +} + +static int ip_address_parse_prefix(ip_address_t* ip, const int family, const char* prefix) { + int r = ip_address_parse_prefix_cidr(ip, family, prefix); + + if (r && family == AF_INET) { + r = ip_address_parse_subnet_mask(ip, prefix); + } + + return r; +} + +static int ip_address_parse_simple(ip_address_t* ip, const int family, const char* address) { + assert(family == AF_INET || family == AF_INET6); + + size_t address_length = strlen(address); + char buffer[address_length + 1]; + strncpy(buffer, address, sizeof(buffer)); + + // Search for a prefix or subnet mask + char* prefix = strchr(buffer, '/'); + if (prefix) { + buffer[prefix - buffer] = '\0'; + prefix++; + } + + memset(&ip->addr, 0, sizeof(ip->addr)); + int r = inet_pton(family, buffer, &ip->addr); + + switch (r) { + // If parsing the IP address failed, we will return false + case 0: + return 1; + + // If the IP address could be successfully parsed, we will + // save the address family and return true + case 1: + ip->family = family; + r = 0; + break; + + default: + return r; + } + + if (prefix) + r = ip_address_parse_prefix(ip, family, prefix); + else + ip->prefix = -1; + + return r; +} + +static int ip_address_parse(ip_address_t* ip, const int family, const char* address) { + static int families[] = { AF_INET, AF_INET6, 0 }; + + int r = 1; + int* f = families; + while (*f) { + if (family == AF_UNSPEC || family == *f) { + r = ip_address_parse_simple(ip, *f, address); + + if (r == 0) + break; + } + + f++; + } + + return r; +} + +static int ip_address_eq(const ip_address_t* a1, const ip_address_t* a2) { + if (a1->family != a2->family) + return 1; + + if (a1->addr != a2->addr) + return 1; + + if (a1->prefix != a2->prefix) + return 1; + + return 0; +} + +static int ip_address_gt(const ip_address_t* a1, const ip_address_t* a2) { + if (a1->family != a2->family || a1->prefix != a2->prefix) + return -1; + + if (a1->addr > a2->addr) + return 0; + + return 1; +} + +static int ip_address_format_string(char* buffer, size_t size, const ip_address_t* ip) { + assert(ip->family == AF_INET || ip->family == AF_INET6); + + const char* p = inet_ntop(ip->family, &ip->addr, buffer, size); + if (!p) + return errno; + + return 0; +} + +static void ip_address_print(const ip_address_t* ip) { + char buffer[INET6_ADDRSTRLEN+4]; + + int r = ip_address_format_string(buffer, sizeof(buffer), ip); + if (r) + return; + + if (ip->prefix >= 0) { + size_t len = strlen(buffer); + snprintf(buffer + len, sizeof(buffer) - len, "/%d", ip->prefix); + } + + printf("%s\n", buffer); +} + +static void ip_address_make_network(ip_address_t* net, const ip_address_t* ip) { + assert(ip->prefix >= 0); + + __uint128_t mask = prefix_to_bitmask(ip->prefix); + + net->family = ip->family; + net->prefix = ip->prefix; + net->addr = ip->addr & mask; +} + +static void ip_address_make_broadcast(ip_address_t* broadcast, const ip_address_t* ip) { + assert(ip->family == AF_INET && ip->prefix >= 0); + + __uint128_t mask = prefix_to_bitmask(ip->prefix); + + broadcast->family = ip->family; + broadcast->prefix = ip->prefix; + broadcast->addr = ip->addr | ~mask; +} + +static int action_check(const int family, const char* address) { + ip_address_t ip; + + int r = ip_address_parse(&ip, family, address); + if (r) + return r; + + // No prefix allowed + return (ip.prefix >= 0); +} + +static int action_equal(const int family, const char* addr1, const char* addr2) { + ip_address_t a1; + ip_address_t a2; + int r; + + r = ip_address_parse(&a1, family, addr1); + if (r) + return 2; + + r = ip_address_parse(&a2, family, addr2); + if (r) + return 2; + + return ip_address_eq(&a1, &a2); +} + +static int action_greater(const int family, const char* addr1, const char* addr2) { + ip_address_t a1; + ip_address_t a2; + int r; + + r = ip_address_parse(&a1, family, addr1); + if (r) + return 2; + + r = ip_address_parse(&a2, family, addr2); + if (r) + return 2; + + return ip_address_gt(&a1, &a2); +} + +static int action_format(const int family, const char* address) { + ip_address_t ip; + + int r = ip_address_parse(&ip, family, address); + if (r) + return r; + + ip_address_print(&ip); + return 0; +} + +static int action_broadcast(const int family, const char* address) { + ip_address_t ip; + int r = ip_address_parse(&ip, family, address); + if (r) { + fprintf(stderr, "Invalid IP address: %s\n", address); + return r; + } + + if (ip.family != AF_INET) { + fprintf(stderr, "This is only possible for IPv4\n"); + return 1; + } + + ip_address_t broadcast; + ip_address_make_broadcast(&broadcast, &ip); + + ip_address_print(&broadcast); + return 0; +} + +static int action_network(const int family, const char* address) { + ip_address_t ip; + + int r = ip_address_parse(&ip, family, address); + if (r) { + fprintf(stderr, "Invalid IP address: %s\n", address); + return r; + } + + ip_address_t network; + ip_address_make_network(&network, &ip); + + ip_address_print(&network); + return 0; +} + +static int action_prefix(const int family, const char* addr1, const char* addr2) { + int r; + + ip_address_t network; + r = ip_address_parse(&network, family, addr1); + if (r) + return r; + + ip_address_t broadcast; + r = ip_address_parse(&broadcast, family, addr2); + if (r) + return r; + + r = ip_address_gt(&broadcast, &network); + if (r) + return r; + + uint32_t mask = ntohl(network.addr ^ broadcast.addr); + int prefix = bitmask_to_prefix(~mask); + if (prefix < 0) + return 1; + + printf("%d\n", prefix); + return 0; +} + +enum actions { + AC_UNSPEC = 0, + AC_BROADCAST, + AC_CHECK, + AC_EQUAL, + AC_FORMAT, + AC_GREATER, + AC_NETWORK, + AC_PREFIX, +}; + +static void set_action(int* action, int what) { + if (*action != AC_UNSPEC) { + printf("Another action has already been selected\n"); + exit(1); + } + + *action = what; +} + +static struct option long_options[] = { + {"broadcast", no_argument, 0, 'b'}, + {"check", no_argument, 0, 'c'}, + {"equal", no_argument, 0, 'e'}, + {"format", no_argument, 0, 'f'}, + {"greater", no_argument, 0, 'g'}, + {"ipv4-only", no_argument, 0, '4'}, + {"ipv6-only", no_argument, 0, '6'}, + {"network", no_argument, 0, 'n'}, + {"prefix", no_argument, 0, 'p'}, + {"verbose", no_argument, 0, 'v'}, + {0, 0, 0, 0} +}; + +int main(int argc, char** argv) { + int option_index = 0; + int required_arguments = 0; + + int verbose = 0; + int action = AC_UNSPEC; + int family = AF_UNSPEC; + + while (1) { + int c = getopt_long(argc, argv, "46bcefgnpv", long_options, &option_index); + if (c == -1) + break; + + switch (c) { + case 0: + if (long_options[option_index].flag != 0) + break; + + printf("option: %s", long_options[option_index].name); + if (optarg) + printf(" with arg %s", optarg); + printf("\n"); + break; + + case '4': + family = AF_INET; + break; + + case '6': + family = AF_INET6; + break; + + case 'b': + set_action(&action, AC_BROADCAST); + required_arguments = 1; + break; + + case 'c': + set_action(&action, AC_CHECK); + required_arguments = 1; + break; + + case 'e': + set_action(&action, AC_EQUAL); + required_arguments = 2; + break; + + case 'f': + set_action(&action, AC_FORMAT); + required_arguments = 1; + break; + + case 'g': + set_action(&action, AC_GREATER); + required_arguments = 2; + break; + + case 'n': + set_action(&action, AC_NETWORK); + required_arguments = 1; + break; + + case 'p': + set_action(&action, AC_PREFIX); + required_arguments = 2; + break; + + case 'v': + verbose = 1; + break; + + case '?': + break; + + default: + abort(); + } + } + + while (optind--) { + argc--; + argv++; + } + + if (argc != required_arguments) { + fprintf(stderr, "Invalid number of arguments. Got %d, required %d.\n", + argc, required_arguments); + return 1; + } + + if (verbose && family != AF_UNSPEC) + printf("Address family = %d\n", family); + + int r = 0; + + switch (action) { + case AC_UNSPEC: + printf("No action specified\n"); + r = 1; + break; + + case AC_BROADCAST: + r = action_broadcast(family, argv[0]); + break; + + case AC_CHECK: + r = action_check(family, argv[0]); + + if (verbose) { + if (r == 0) + printf("%s is a valid IP address\n", argv[0]); + else + printf("%s is not a valid IP address\n", argv[0]); + } + break; + + case AC_EQUAL: + r = action_equal(family, argv[0], argv[1]); + + if (verbose) { + if (r == 0) + printf("%s equals %s\n", argv[0], argv[1]); + else if (r == 2) + printf("Invalid IP address provided\n"); + else + printf("%s does not equal %s\n", argv[0], argv[1]); + } + break; + + case AC_FORMAT: + r = action_format(family, argv[0]); + + if (verbose && r) + printf("Invalid IP address given\n"); + + break; + + case AC_GREATER: + r = action_greater(family, argv[0], argv[1]); + + if (verbose) { + if (r == 0) + printf("%s is greater than %s\n", argv[0], argv[1]); + else if (r == 2) + printf("Invalid IP address provided\n"); + else + printf("%s is not greater than %s\n", argv[0], argv[1]); + } + break; + + case AC_NETWORK: + r = action_network(family, argv[0]); + break; + + case AC_PREFIX: + r = action_prefix(family, argv[0], argv[1]); + break; + } + + return r; +} -- 2.39.2