summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniil Baturin <daniil@baturin.org>2013-05-25 21:58:25 -0700
committerDaniil Baturin <daniil@baturin.org>2013-05-25 21:58:25 -0700
commitaa7c28da716b15d8220c2af6b9448e033b176b98 (patch)
tree724b5d579b90390513e793c6549973cf2a061c9d
parenta95eae0bfe26c20be3fd84871ce14c861d505c19 (diff)
downloadipaddrcheck-aa7c28da716b15d8220c2af6b9448e033b176b98.tar.gz
ipaddrcheck-aa7c28da716b15d8220c2af6b9448e033b176b98.zip
Fix previous commit.
TODO: Get some sleep.
-rw-r--r--src/Makefile.am9
-rw-r--r--src/iptest.c264
-rw-r--r--src/iptest.h261
3 files changed, 444 insertions, 90 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index bda48fb..f30438f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,6 +1,7 @@
-AM_CFLAGS = --pedantic -Wall -Werror -std=c99 -O2 -lcidr
-AM_LDFLAGS =
+AM_CFLAGS = --pedantic -Wall -Werror -std=c99 -O2
+AM_LDFLAGS =
-iptest_SOURCES = iptest.c iptest.h
+ipaddrcheck_SOURCES = iptest.c iptest.h
+ipaddrcheck_LDFLAGS = -lcidr -lpcre
-bin_PROGRAMS = iptest
+bin_PROGRAMS = ipaddrcheck
diff --git a/src/iptest.c b/src/iptest.c
index 5087736..c2a7266 100644
--- a/src/iptest.c
+++ b/src/iptest.c
@@ -19,99 +19,259 @@
*
*/
+#include <errno.h>
#include "config.h"
#include "iptest.h"
static const struct option options[] =
{
- { "is-valid", required_argument, NULL, 'a' },
- { "is-ipv4", required_argument, NULL, 'b' },
- { "is-ipv4-host", required_argument, NULL, 'c'},
- { "is-ipv4-net", required_argument, NULL, 'd'},
- { "is-ipv6", required_argument, NULL, 'g' },
- { "is-ipv6-net", required_argument, NULL, 'G' },
- { NULL, no_argument, NULL, 0 }
+ { "is-valid", no_argument, NULL, 'a' },
+ { "has-mask", no_argument, NULL, 'b' },
+ { "is-ipv4", no_argument, NULL, 'c' },
+ { "is-ipv4-cidr", no_argument, NULL, 'd' },
+ { "is-ipv4-single", no_argument, NULL, 'e' },
+ { "is-ipv4-host", no_argument, NULL, 'f' },
+ { "is-ipv4-net", no_argument, NULL, 'g' },
+ { "is-ipv4-broadcast", no_argument, NULL, 'h' },
+ { "is-ipv4-multicast", no_argument, NULL, 'i' },
+ { "is-ipv4-loopback", no_argument, NULL, 'j' },
+ { "is-ipv4-link-local", no_argument, NULL, 'k' },
+ { "is-ipv4-rfc1918", no_argument, NULL, 'l' },
+ { "is-ipv6", no_argument, NULL, 'm' },
+ { "is-ipv6-cidr", no_argument, NULL, 'n' },
+ { "is-ipv6-single", no_argument, NULL, 'o' },
+ { "is-ipv6-host", no_argument, NULL, 'p' },
+ { "is-ipv6-net", no_argument, NULL, 'r' },
+ { "is-ipv6-multicast", no_argument, NULL, 's' },
+ { "is-ipv6-link-local", no_argument, NULL, 't' },
+ { "is-valid-intf-address", no_argument, NULL, 'u' },
+ { "version", no_argument, NULL, 'z' },
+ { NULL, no_argument, NULL, 0 }
};
-void help(void)
-{
- static char *message = \
-"--is-valid STR Check if STR is a valid IPv4 or IPv6 address\n\
- or subnet\n\
---is-ipv4 STR Check if STR is a valid IPv4 address with mask\n";
-
- printf("%s", message);
-}
+/* Auxillary functions */
+static void print_help(void);
+static void print_version(void);
int main(int argc, char* argv[])
{
- char *address_str = "";
- int action = 0;
+ char *address_str = ""; /* IP address string obtained from arguments */
+ int action = 0; /* Action associated with given check option */
+ int* actions; /* Array of all given actions */
+ int action_count = 0; /* Actions array size */
+
+ int option_index = 0; /* Number of the current option for getopt call */
+ int optc; /* Option character for getopt call */
+
+ /* Parse options, convert to action codes, store in array */
- int option_index = 0;
- char c;
- int option_count = 0;
+ /* Try to allocate memory for the actions array, abort if fail */
+ actions = (int*)calloc(argc, sizeof(int));
+ if( errno == ENOMEM )
+ {
+ fprintf(stderr, "Error: could not allocate memory!\n");
+ return(EXIT_FAILURE);
+ }
- while( (c = getopt_long(argc, argv, "abcd?", options, &option_index)) != -1 )
+ while( (optc = getopt_long(argc, argv, "abcdv?", options, &option_index)) != -1 )
{
- switch(c)
+ switch(optc)
{
case 'a':
action = IS_VALID;
- address_str = optarg;
break;
case 'b':
- action = IS_IPV4;
- address_str = optarg;
+ action = HAS_MASK;
break;
case 'c':
- action = IS_IPV4_HOST;
- address_str = optarg;
+ action = IS_IPV4;
break;
case 'd':
+ action = IS_IPV4_CIDR;
+ break;
+ case 'e':
+ action = IS_IPV4_SINGLE;
+ break;
+ case 'f':
+ action = IS_IPV4_HOST;
+ break;
+ case 'g':
action = IS_IPV4_NET;
- address_str = optarg;
+ case 'h':
+ action = IS_IPV4_BROADCAST;
break;
- case 'I':
+ case 'i':
+ action = IS_IPV4_MULTICAST;
+ break;
+ case 'j':
+ action = IS_IPV4_LOOPBACK;
+ break;
+ case 'k':
+ action = IS_IPV4_LINKLOCAL;
+ break;
+ case 'l':
+ action = IS_IPV4_RFC1918;
+ break;
+ case 'm':
action = IS_IPV6;
- address_str = optarg;
+ break;
+ case 'n':
+ action = IS_IPV6_CIDR;
+ break;
+ case 'o':
+ action = IS_IPV6_SINGLE;
+ break;
+ case 'p':
+ action = IS_IPV6_HOST;
+ break;
+ case 'r':
+ action = IS_IPV6_NET;
+ break;
+ case 's':
+ action = IS_IPV6_MULTICAST;
+ break;
+ case 't':
+ action = IS_IPV6_LINKLOCAL;
+ break;
+ case 'u':
+ action = IS_VALID_INTF_ADDR;
break;
case '?':
+ print_help();
+ return(0);
+ case 'z':
+ print_version();
+ return(0);
default:
- fprintf(stderr, "Invalid option\n");
+ fprintf(stderr, "Error: invalid option\n");
break;
}
- option_count++;
+
+ action_count = optind-2;
+ actions[action_count] = action;
}
- if( option_count != 1 )
+ /* Get non-option arguments */
+ if( (argc - optind) == 1 )
+ {
+ address_str = argv[optind];
+ printf("%s\n", address_str);
+ }
+ else
{
- fprintf(stderr, "Wrong options number, exactly one option expected!\n");
- help();
- return(1);
+ printf("Error: wrong number of arguments, one argument required!\n");
+ return(EXIT_FAILURE);
}
CIDR *address;
address = cidr_from_str(address_str);
- int result = EXIT_FAILURE;
+ int result = RESULT_SUCCESS;
+
+ /* Check if the address is valid at all,
+ if not there is no point in going further */
+ if( is_valid_address(address) != RESULT_SUCCESS )
+ {
+ return(EXIT_FAILURE);
+ }
- switch(action)
+ printf("action_count: %d\n", action_count);
+ while( (action_count >= 0) && (result == RESULT_SUCCESS) )
{
- case IS_VALID:
- result = is_valid_address(address);
- break;
- case IS_IPV4:
- result = is_ipv4(address);
- break;
- case IS_IPV4_HOST:
- result = is_ipv4_host(address);
- break;
- case IS_IPV4_NET:
- result = is_ipv4_net(address);
- break;
+ switch(actions[action_count])
+ {
+ case IS_VALID:
+ result = is_valid_address(address);
+ break;
+ case HAS_MASK:
+ result = has_mask(address_str);
+ break;
+ case IS_IPV4:
+ result = is_ipv4(address);
+ break;
+ case IS_IPV4_CIDR:
+ result = is_ipv4_cidr(address_str);
+ break;
+ case IS_IPV4_SINGLE:
+ if( !(is_ipv4(address) && has_mask(address_str)) )
+ {
+ result = RESULT_FAILURE;
+ }
+ /* No need to change it in case of success */
+ break;
+ case IS_IPV4_HOST:
+ result = is_ipv4_host(address);
+ printf("rsult %d\n", result);
+ break;
+ case IS_IPV4_NET:
+ /* XXX: Should we fail this check for single addresses? */
+ result = is_ipv4_net(address);
+ break;
+ case IS_IPV4_BROADCAST:
+ result = is_ipv4_broadcast(address);
+ break;
+ case IS_IPV4_MULTICAST:
+ result = is_ipv4_multicast(address);
+ break;
+ case IS_IPV4_LOOPBACK:
+ result = is_ipv4_loopback(address);
+ break;
+ case IS_IPV4_LINKLOCAL:
+ result = is_ipv4_link_local(address);
+ break;
+ case IS_IPV4_RFC1918:
+ result = is_ipv4_rfc1918(address);
+ break;
+ case IS_IPV6:
+ result = is_ipv6(address);
+ break;
+ case IS_IPV6_HOST:
+ result = is_ipv6_host(address);
+ break;
+ case IS_IPV6_NET:
+ result = is_ipv6_net(address);
+ break;
+ }
+ printf("action: %d\n", actions[action_count]);
+ action_count--;
}
- return(result);
+ /* Clean up */
+ free(actions);
+ cidr_free(address);
+
+ if( result == RESULT_SUCCESS )
+ {
+ return(EXIT_SUCCESS);
+ }
+ else
+ {
+ return(EXIT_FAILURE);
+ }
+}
+
+/*
+ * Print help, no other side effects
+ */
+void print_help(void)
+{
+ static const char *message = \
+"--is-valid STR Check if STR is a valid IPv4 or IPv6 address\n\
+ or subnet\n\
+--is-ipv4 STR Check if STR is a valid IPv4 address with mask\n";
+
+ printf("%s", message);
+}
+
+/*
+ * Print version information, no other side effects
+ */
+void print_version(void)
+{
+ printf("%s %s\n", PACKAGE_NAME, PACKAGE_VERSION);
+ printf("Copyright (C) Free Software Foundation, Inc.\n\
+License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\n\
+This is free software: you are free to change and redistribute it.\n\
+There is NO WARRANTY, to the extent permitted by law.\n");
}
diff --git a/src/iptest.h b/src/iptest.h
index 3624ec4..f025911 100644
--- a/src/iptest.h
+++ b/src/iptest.h
@@ -1,48 +1,133 @@
/*
- * iptest.h: macros and functions for iptest IPv4/IPv6 validator
+ * ipaddrcheck.h: macros and functions for iptest IPv4/IPv6 validator
*
* Maintainer: Daniil Baturin <daniil at baturin dot org>
*
* Copyright (C) 2013 SO3Group
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
*
- * This program is distributed in the hope that it will be useful,
+ * This library 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.
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser 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 <http://www.gnu.org/licenses/>.
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
*
*/
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <getopt.h>
+#include <pcre.h>
#include <libcidr.h>
#define INVALID_PROTO -1
/* Option codes */
-#define IS_VALID 10
-#define IS_IPV4 20
-#define IS_IPV4_HOST 30
-#define IS_IPV4_NET 40
-#define IS_IPV4_BROADCAST 50
-#define IS_IPV4_UNICAST 60
-#define IS_IPV4_MULTICAST 70
-#define IS_IPV4_RFC1918 80
-#define IS_IPV4_LOOPBACK 85
-#define IS_IPV6 90
-#define IS_IPV6_HOST 100
-#define IS_IPV6_NET 110
-#define IS_IPV6_UNICAST 120
-#define IS_IPV6_MULTICAST 130
-#define IS_IPV6_LINKLOCAL 140
+#define IS_VALID 10
+#define IS_IPV4 20
+#define IS_IPV4_CIDR 30
+#define IS_IPV4_SINGLE 40
+#define IS_IPV4_HOST 50
+#define IS_IPV4_NET 60
+#define IS_IPV4_BROADCAST 70
+#define IS_IPV4_UNICAST 80
+#define IS_IPV4_MULTICAST 90
+#define IS_IPV4_RFC1918 100
+#define IS_IPV4_LOOPBACK 110
+#define IS_IPV4_LINKLOCAL 120
+#define IS_IPV6 130
+#define IS_IPV6_CIDR 140
+#define IS_IPV6_SINGLE 150
+#define IS_IPV6_HOST 160
+#define IS_IPV6_NET 170
+#define IS_IPV6_UNICAST 180
+#define IS_IPV6_MULTICAST 190
+#define IS_IPV6_LINKLOCAL 200
+#define HAS_MASK 210
+#define IS_VALID_INTF_ADDR 220
+
+#define RESULT_SUCCESS 1
+#define RESULT_FAILURE 0
+
+#define IPV4_MULTICAST "224.0.0.0/4"
+#define IPV4_LOOPBACK "127.0.0.0/8"
+#define IPV4_LINKLOCAL "169.254.0.0/16"
+#define IPV4_RFC1918_A "10.0.0.0/8"
+#define IPV4_RFC1918_B "172.16.0.0/12"
+#define IPV4_RFC1918_C "192.168.0.0/16"
+
+/*
+ * Address string functions
+ *
+ * Note that they perform format check only
+ * and must not be used to deermine if it's
+ * a valid address, only what type of address
+ * format it is.
+ *
+ * The only reason they exist is that libcidr
+ * is very liberal on its input format and
+ * doesn't provide any information on what
+ * the format was.
+ */
+
+/* Does it have mask? */
+int has_mask(char* address_str)
+{
+ int result;
+ char *hasslash = strchr(address_str, '/');
+
+ if( hasslash != NULL )
+ {
+ result = RESULT_SUCCESS;
+ }
+ else
+ {
+ result = RESULT_FAILURE;
+ }
+
+ return(result);
+}
+
+/* Does it look like IPv4 CIDR (e.g. 192.0.2.1/24)? */
+int is_ipv4_cidr(char* address_str)
+{
+ int result;
+
+ int offsets[1];
+ pcre *re;
+ int rc;
+ const char *error;
+ int erroffset;
+
+ re = pcre_compile("^\\d{1,3}.\\d{1,3}.\\d{1,3}.\\d{1,3}/\\d{1,2}$",
+ 0, &error, &erroffset, NULL);
+ rc = pcre_exec(re, NULL, address_str, strlen(address_str), 0, 0, offsets, 1);
+
+ if( rc < 0 )
+ {
+ result = RESULT_FAILURE;
+ }
+ else
+ {
+ result = RESULT_SUCCESS;
+ }
+
+ return(result);
+}
+
+
+/*
+ * Address checking functions that rely on libcidr
+ */
/* Does it look like a valid address of any protocol? */
int is_valid_address(CIDR *address)
@@ -51,11 +136,11 @@ int is_valid_address(CIDR *address)
if( cidr_get_proto(address) != INVALID_PROTO )
{
- result = EXIT_SUCCESS;
+ result = RESULT_SUCCESS;
}
else
{
- result = EXIT_FAILURE;
+ result = RESULT_FAILURE;
}
return(result);
@@ -69,11 +154,11 @@ int is_ipv4(CIDR *address)
if( cidr_get_proto(address) == CIDR_IPV4 )
{
- result = EXIT_SUCCESS;
+ result = RESULT_SUCCESS;
}
else
{
- result = EXIT_FAILURE;
+ result = RESULT_FAILURE;
}
return(result);
@@ -85,13 +170,14 @@ int is_ipv4_host(CIDR *address)
int result;
if( (cidr_get_proto(address) == CIDR_IPV4) &&
- cidr_equals(address, cidr_addr_network(address)) )
+ ((cidr_equals(address, cidr_addr_network(address)) < 0) ||
+ (cidr_get_pflen(address) == 32)) )
{
- result = EXIT_SUCCESS;
+ result = RESULT_SUCCESS;
}
else
{
- result = EXIT_FAILURE;
+ result = RESULT_FAILURE;
}
return(result);
@@ -100,18 +186,125 @@ int is_ipv4_host(CIDR *address)
/* Is it a correct IPv4 network address? */
int is_ipv4_net(CIDR *address)
{
- /* TODO: Don't try to validate is mask is not present */
int result;
if( (cidr_get_proto(address) == CIDR_IPV4) &&
(cidr_equals(address, cidr_addr_network(address)) == 0) )
{
- result = EXIT_SUCCESS;
+ result = RESULT_SUCCESS;
+ }
+ else
+ {
+ result = RESULT_FAILURE;
+ }
+
+ return(result);
+}
+
+/* Is it an IPv4 broadcast address? */
+int is_ipv4_broadcast(CIDR *address)
+{
+ int result;
+
+ if( cidr_equals(address, cidr_addr_broadcast(address)) == 0 )
+ {
+ result = RESULT_SUCCESS;
+ }
+ else
+ {
+ result = RESULT_FAILURE;
+ }
+
+ return(result);
+}
+
+/* Is it an IPv4 multicast address? */
+int is_ipv4_multicast(CIDR *address)
+{
+ int result;
+
+ if( (cidr_get_proto(address) == CIDR_IPV4) &&
+ (cidr_contains(cidr_from_str(IPV4_MULTICAST), address) == 0) )
+ {
+ result = RESULT_SUCCESS;
+ }
+ else
+ {
+ result = RESULT_FAILURE;
+ }
+
+ return(result);
+}
+
+/* Is it an IPv4 loopback address? */
+int is_ipv4_loopback(CIDR *address)
+{
+ int result;
+
+ if( (cidr_get_proto(address) == CIDR_IPV4) &&
+ (cidr_contains(cidr_from_str(IPV4_LOOPBACK), address) == 0) )
+ {
+ result = RESULT_SUCCESS;
}
else
{
- result = EXIT_FAILURE;
+ result = RESULT_FAILURE;
}
return(result);
}
+
+/* Is it an IPv4 link-local address? */
+int is_ipv4_link_local(CIDR *address)
+{
+ int result;
+
+ if( (cidr_get_proto(address) == CIDR_IPV4) &&
+ (cidr_contains(cidr_from_str(IPV4_LINKLOCAL), address) == 0) )
+ {
+ result = RESULT_SUCCESS;
+ }
+ else
+ {
+ result = RESULT_FAILURE;
+ }
+
+ return(result);
+}
+
+/* Is it an IPv4 RFC1918 address? */
+int is_ipv4_rfc1918(CIDR *address)
+{
+ int result;
+
+ if( (cidr_get_proto(address) == CIDR_IPV4) &&
+ ( (cidr_contains(cidr_from_str(IPV4_RFC1918_A), address) == 0) ||
+ (cidr_contains(cidr_from_str(IPV4_RFC1918_B), address) == 0) ||
+ (cidr_contains(cidr_from_str(IPV4_RFC1918_C), address) == 0) ) )
+ {
+ result = RESULT_SUCCESS;
+ }
+ else
+ {
+ result = RESULT_FAILURE;
+ }
+
+ return(result);
+}
+
+/* is it a correct IPv6 host or subnet address,
+ with or withour mask */
+int is_ipv6(CIDR *address)
+{
+ return RESULT_FAILURE;
+}
+
+int is_ipv6_host(CIDR *address)
+{
+ return RESULT_FAILURE;
+}
+
+int is_ipv6_net(CIDR *address)
+{
+ return RESULT_FAILURE;
+}