summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Hemminger <stephen.hemminger@vyatta.com>2010-11-22 09:33:38 -0800
committerStephen Hemminger <stephen.hemminger@vyatta.com>2010-11-22 10:42:26 -0800
commitcb55706633bda6c5bd7c8391da9193ad0146002b (patch)
tree236d75d4f3a7a2911f3609eb0f983f1e189f53ea
parentfb1bf8a2eefbdb467a948688ab388628455ef480 (diff)
downloadvyatta-cfg-system-cb55706633bda6c5bd7c8391da9193ad0146002b.tar.gz
vyatta-cfg-system-cb55706633bda6c5bd7c8391da9193ad0146002b.zip
Add utilities checking addresses
These are new C language utilites to replace the Perl utility when checking interface addresses. Perl compilation is major component of slow boot time. Note: this changes the package from pure scripts (arch independent) to arch dependent
-rw-r--r--.gitignore43
-rw-r--r--Makefile.am6
-rw-r--r--configure.ac4
-rw-r--r--debian/control9
-rw-r--r--src/local_ip.c64
-rw-r--r--src/valid_address.c153
6 files changed, 257 insertions, 22 deletions
diff --git a/.gitignore b/.gitignore
index 482617d0..3c8b8c29 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,21 +3,28 @@
*#
*~
.*.swp
-/aclocal.m4
-/autom4te.cache
-/build-stamp
-/config
-/config.log
-/config.guess
-/config.status
-/config.sub
-/configure
-/debian/files
-/debian/vyatta-cfg-system
-/debian/vyatta-cfg-system.postinst
-/debian/*.log
-/debian/*.substvars
-/INSTALL
-/Makefile.in
-/Makefile
-
+*.[oa]
+*.l[oa]
+*.so
+*.libs
+*.deps
+.dirstamp
+aclocal.m4
+autom4te.cache
+build-stamp
+config
+config.log
+config.guess
+config.status
+config.sub
+configure
+debian/files
+debian/vyatta-cfg-system
+debian/vyatta-cfg-system.postinst
+debian/*.log
+debian/*.substvars
+INSTALL
+Makefile.in
+Makefile
+src/valid_address
+src/local_ip
diff --git a/Makefile.am b/Makefile.am
index 3d4175c6..a2635328 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -61,6 +61,12 @@ sbin_SCRIPTS += scripts/vyatta-bridgegroup-depedency.pl
sbin_SCRIPTS += scripts/vyatta-dhcpv6-client.pl
sbin_SCRIPTS += scripts/vyatta-update-grub.pl
+sbin_PROGRAMS = src/valid_address
+sbin_PROGRAMS += src/local_ip
+
+src_valid_address = src/valid_address.c
+src_local_ip = src/local_ip.c
+
share_perl5_DATA = lib/Vyatta/Login/User.pm
share_perl5_DATA += lib/Vyatta/Login/RadiusServer.pm
diff --git a/configure.ac b/configure.ac
index 39771f0a..f7417452 100644
--- a/configure.ac
+++ b/configure.ac
@@ -26,5 +26,9 @@ AC_CONFIG_FILES(
AC_SUBST(NOSTRIP)
+AC_PROG_CC
+AC_PROG_CXX
+AM_PROG_AS
+AM_PROG_CC_C_O
AC_OUTPUT
diff --git a/debian/control b/debian/control
index 8b3aac01..4f8d26c5 100644
--- a/debian/control
+++ b/debian/control
@@ -6,16 +6,17 @@ Build-Depends: debhelper (>= 5), autotools-dev
Standards-Version: 3.7.2
Package: vyatta-cfg-system
-Architecture: all
+Architecture: any
Depends: acpid,
adduser,
sed (>= 4.1.5),
- perl (>= 5.8.8),
+ perl (>= 5.10.1),
libnetaddr-ip-perl,
procps (>= 1:3.2.7-3),
coreutils (>= 5.97-5.3),
libpam-radius-auth,
vyatta-cfg (>= 0.18),
+ libc6 (>= 2.7-6),
libpam-runtime (>= 1.0.1-5),
vyatta-bash | bash (>= 3.1),
sysv-rc,
@@ -58,5 +59,5 @@ Suggests: util-linux (>= 2.13-5),
ntpdate
Replaces: vyatta-cfg (<< 0.17.33),
vyatta-cfg-quagga (<< 0.18.17)
-Description: Vyatta system-level configuration templates/scripts
- Vyatta system-level configuration templates and scripts.
+Description: Vyatta system-level configuration
+ Vyatta system-level configuration utiliites, templates and scripts.
diff --git a/src/local_ip.c b/src/local_ip.c
new file mode 100644
index 00000000..3707559f
--- /dev/null
+++ b/src/local_ip.c
@@ -0,0 +1,64 @@
+/*
+ * Test if an IP address is assigned to the local system
+ *
+ * This uses the fact Linux will not allow binding to an address that
+ * is not on the system. It is much faster than scanning all the
+ * interface addresses.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+int main(int argc, char **argv)
+{
+ int af, s;
+
+ if (argc != 2) {
+ fprintf(stderr, "Usage: %s x.x.x.x\n", argv[0]);
+ return -1;
+ }
+
+ af = strchr(argv[1], ':') ? AF_INET6 : AF_INET;
+ s = socket(af, SOCK_STREAM, 0);
+ if (s < 0) {
+ perror("socket");
+ return -1;
+ }
+
+ if (af == AF_INET) {
+ struct sockaddr_in sin = {
+ .sin_family = AF_INET,
+ };
+
+ if (inet_pton(af, argv[1], &sin.sin_addr) <= 0) {
+ fprintf(stderr, "%s: invalid address\n", argv[1]);
+ return -1;
+ }
+
+ if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
+ if (errno == EADDRNOTAVAIL)
+ return 1;
+ perror("bind");
+ return -1;
+ }
+ } else {
+ struct sockaddr_in6 sin6;
+
+ if (inet_pton(af, argv[1], &sin6.sin6_addr) <= 0) {
+ fprintf(stderr, "%s: invalid address\n", argv[1]);
+ return -1;
+ }
+
+ if (bind(s, (struct sockaddr *)&sin6, sizeof(sin6)) < 0) {
+ if (errno == EADDRNOTAVAIL)
+ return 1;
+ perror("bind");
+ return -1;
+ }
+ }
+ return 0;
+}
diff --git a/src/valid_address.c b/src/valid_address.c
new file mode 100644
index 00000000..a98d0f56
--- /dev/null
+++ b/src/valid_address.c
@@ -0,0 +1,153 @@
+/*
+ * **** License ****
+ * 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 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.
+ * #
+ * A copy of the GNU General Public License is available as
+ * `/usr/share/common-licenses/GPL' in the Debian GNU/Linux distribution
+ * or on the World Wide Web at `http://www.gnu.org/copyleft/gpl.html'.
+ * You can also obtain it by writing to the Free Software Foundation,
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * This code was originally developed by Vyatta, Inc.
+ * Portions created by Vyatta are Copyright (C) 2007 Vyatta, Inc.
+ * All Rights Reserved.
+ *
+ * This code validates IPv4 and IPv6 network prefixes using
+ * the same rules as the iproute utilities. It is a replacement
+ * for earlier perl code which did not scale well.
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <string.h>
+#include <stdlib.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+/*
+ * Note: this code requires full four-tuple when specifying IPv4
+ * address because the iproute utilites uses a non-standard parsing
+ * (ie not inet_aton, or inet_pton)
+ * because of legacy choice to parse 10.8 as 10.8.0.0 not 10.0.0.8
+ */
+static int valid_ipv4(const char *str)
+{
+ int i;
+ unsigned int a[4], plen;
+ uint32_t addr; /* host order */
+
+ if (sscanf(str, "%u.%u.%u.%u/%u", &a[0], &a[1], &a[2], &a[3], &plen)
+ != 5)
+ goto bad_addr;
+
+ addr = 0;
+ for (i = 0; i < 4; i++) {
+ if (a[i] > 255)
+ goto bad_addr;
+ addr <<= 8;
+ addr |= a[i];
+ }
+
+ if (plen == 0 || plen > 32) {
+ fprintf(stderr,
+ "Invalid prefix len %d for IP\n", plen);
+ return 0;
+ }
+
+ if (~addr == 0) {
+ fprintf(stderr,
+ "Can not assign broadcast address as IP address\n");
+ return 0;
+ }
+
+ if (plen < 31) {
+ uint32_t net_mask = ~0 << (32 - plen);
+ if ((addr & net_mask) == addr) {
+ fprintf(stderr,
+ "Can not assign network address as IP address\n");
+ return 0;
+ }
+ }
+ return 1;
+
+ bad_addr:
+ fprintf(stderr, "Invalid IPv4 address/prefix\n");
+ return 0;
+}
+
+static int valid_ipv6(char *str)
+{
+ unsigned int prefix_len;
+ struct in6_addr addr; /* net order */
+ char *slash, *endp;
+
+ slash = strchr(str, '/');
+ if (!slash)
+ goto bad_addr; /* Missing slash */
+
+ *slash++ = 0;
+ prefix_len = strtoul(slash, &endp, 10);
+ if (*slash == '\0' || *endp != '\0')
+ goto bad_addr; /* Non-digit in prefix length */
+
+ if (inet_pton(AF_INET6, str, &addr) <= 0)
+ goto bad_addr; /* Not a valid IPv6 address */
+
+ if (IN6_IS_ADDR_LINKLOCAL(&addr)) {
+ fprintf(stderr,
+ "Can not assign an address reserved for IPv6 link local\n");
+ return 0;
+ }
+
+ if (IN6_IS_ADDR_MULTICAST(&addr)) {
+ fprintf(stderr,
+ "Can not assign an address reserved for IPv6 multicast\n");
+ return 0;
+ }
+
+ if (prefix_len <= 1 || prefix_len > 128) {
+ fprintf(stderr,
+ "Invalid prefix len %d for IPv6\n", prefix_len);
+ return 0;
+ }
+
+ if (prefix_len == 128) {
+ fprintf(stderr,
+ "Can not assign IPv6 Unspecified address\n");
+ return 0;
+ }
+ return 1;
+
+ bad_addr:
+ fprintf(stderr, "Invalid IPv6 address/prefix\n");
+ return 0;
+}
+
+
+static int valid_prefix(char *str)
+{
+ if (strcmp(str, "dhcp") == 0 || strcmp(str, "dhcpv6") == 0)
+ return 1;
+
+ if (strchr(str, ':') == NULL)
+ return valid_ipv4(str);
+ else
+ return valid_ipv6(str);
+}
+
+int main(int argc, char **argv)
+{
+ while (--argc) {
+ if (!valid_prefix(*++argv))
+ return 1;
+ }
+ return 0;
+}