+2004-12-28 Michael Poole <mdpoole@troilus.org>
+
+ * include/res.h: Implement irc_in_addr_* as macros.
+
+ * ircd/ircd_res.c: Remove the function bodies.
+
+ * ircd/ircd_string.c (irc_in_addr_is_ipv4): Remove body.
+ (ircd_ntoa_r): Do not append extra ':' when unparsing 0::.
+ (ircd_aton): Accept IPv6 addresses with all eight segments
+ specified (e.g. 0:0:0:0:0:0:0:0). Correctly parse addresses
+ with IPv4 bits at the end (e.g. ::FFFF:127.0.0.1).
+
+ * ircd/test/ircd_in_addr_t.c, ircd/test/test_stub.c: New files.
+
+ * ircd/test/Makefile: Convert to Makefile.in for proper VPATH
+ support. Add test_stub.c and ircd_in_addr_t.c references.
+
+ * configure.in: Generate ircd/test/Makefile as an output file.
+
+ * configure: Update.
+
2004-12-18 Michael Poole <mdpoole@troilus.org>
* include/client.h: Move unreg, privs, capab and active fields
_ACEOF
- ac_config_files="$ac_config_files Makefile ircd/Makefile doc/Makefile"
+ ac_config_files="$ac_config_files Makefile ircd/Makefile ircd/test/Makefile doc/Makefile"
ac_config_commands="$ac_config_commands default"
cat >confcache <<\_ACEOF
# This file is a shell script that caches the results of configure
# Handling of arguments.
"Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile" ;;
"ircd/Makefile" ) CONFIG_FILES="$CONFIG_FILES ircd/Makefile" ;;
+ "ircd/test/Makefile" ) CONFIG_FILES="$CONFIG_FILES ircd/test/Makefile" ;;
"doc/Makefile" ) CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;;
"default" ) CONFIG_COMMANDS="$CONFIG_COMMANDS default" ;;
"config.h" ) CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
[Maximum number of network connections])
dnl Finally really generate all output files:
-AC_OUTPUT(Makefile ircd/Makefile doc/Makefile, [echo timestamp > stamp-h])
+AC_OUTPUT(Makefile ircd/Makefile ircd/test/Makefile doc/Makefile, [echo timestamp > stamp-h])
dnl Report configuration
AC_OUTPUT_COMMANDS([echo "
extern void gethost_byname(const char *name, const struct DNSQuery *query);
extern void gethost_byaddr(const struct irc_in_addr *addr, const struct DNSQuery *query);
-extern int irc_in_addr_valid(const struct irc_in_addr *addr);
-extern int irc_in_addr_cmp(const struct irc_in_addr *a, const struct irc_in_addr *b);
-extern int irc_in_addr_is_ipv4(const struct irc_in_addr *addr);
-extern int irc_in_addr_is_loopback(const struct irc_in_addr *addr);
+/** Evaluate to non-zero if \a ADDR is a valid address (not all 0s and not all 1s). */
+#define irc_in_addr_valid(ADDR) (((ADDR)->in6_16[0] && ~(ADDR)->in6_16[0]) \
+ || (ADDR)->in6_16[1] != (ADDR)->in6_16[0] \
+ || (ADDR)->in6_16[2] != (ADDR)->in6_16[0] \
+ || (ADDR)->in6_16[3] != (ADDR)->in6_16[0] \
+ || (ADDR)->in6_16[4] != (ADDR)->in6_16[0] \
+ || (ADDR)->in6_16[5] != (ADDR)->in6_16[0] \
+ || (ADDR)->in6_16[6] != (ADDR)->in6_16[0] \
+ || (ADDR)->in6_16[7] != (ADDR)->in6_16[0])
+/** Evaluate to non-zero if \a ADDR (of type struct irc_in_addr) is an IPv4 address. */
+#define irc_in_addr_is_ipv4(ADDR) (!(ADDR)->in6_16[0] && !(ADDR)->in6_16[1] && !(ADDR)->in6_16[2] \
+ && !(ADDR)->in6_16[3] && !(ADDR)->in6_16[4] && (ADDR)->in6_16[6] \
+ && (!(ADDR)->in6_16[5] || (ADDR)->in6_16[5] == 65535))
+/** Evaluate to non-zero if \a A is a different IP than \a B. */
+#define irc_in_addr_cmp(A,B) (irc_in_addr_is_ipv4(A) ? ((A)->in6_16[6] != (B)->in6_16[6] \
+ || (A)->in6_16[7] != (B)->in6_16[7] || !irc_in_addr_is_ipv4(B)) \
+ : memcmp((A), (B), sizeof(struct irc_in_addr)))
+/** Evaluate to non-zero if \a ADDR is a loopback address. */
+#define irc_in_addr_is_loopback(ADDR) (!(ADDR)->in6_16[0] && !(ADDR)->in6_16[1] && !(ADDR)->in6_16[2] \
+ && !(ADDR)->in6_16[3] && !(ADDR)->in6_16[4] \
+ && ((!(ADDR)->in6_16[5] \
+ && ((!(ADDR)->in6_16[6] && (ADDR)->in6_16[7] == htons(1)) \
+ || (ntohs((ADDR)->in6_16[6]) & 0xff00) == 0x7f00)) \
+ || (((ADDR)->in6_16[5] == 65535) \
+ && (ntohs((ADDR)->in6_16[6]) & 0xff00) == 0x7f00)))
#endif
":Resolver: requests %d(%d)", request_count, request_mem);
return request_mem;
}
-
-/** Check whether an address looks valid.
- * This means not all 0s and not all 1s.
- * @param[in] addr Address to check for validity.
- * @return Non-zero if the address looks valid.
- */
-int irc_in_addr_valid(const struct irc_in_addr *addr)
-{
- unsigned int ii;
- unsigned short val;
-
- val = addr->in6_16[0];
- if (val != 0 && val != 0xffff)
- return 1;
- for (ii = 1; ii < 8; ii++)
- if (addr->in6_16[ii] != val)
- return 1;
- return 0;
-}
-
-/** Compare two IP addresses.
- * @param[in] a First address to compare.
- * @param[in] b Second address to compare.
- * @return Non-zero if the two addresses differ, zero if they are identical.
- */
-int irc_in_addr_cmp(const struct irc_in_addr *a, const struct irc_in_addr *b)
-{
- if (irc_in_addr_is_ipv4(a))
- return a->in6_16[6] != b->in6_16[6]
- || a->in6_16[7] != b->in6_16[7]
- || !irc_in_addr_is_ipv4(b);
- else
- return memcmp(a, b, sizeof(*a));
-}
-
-/** Indicate whether an IP address is a loopback address.
- * @param[in] addr Address to check.
- * @return Non-zero if the address is loopback; zero if not.
- */
-int irc_in_addr_is_loopback(const struct irc_in_addr *addr)
-{
- if (addr->in6_16[0] != 0
- || addr->in6_16[1] != 0
- || addr->in6_16[2] != 0
- || addr->in6_16[3] != 0
- || addr->in6_16[4] != 0)
- return 0;
- if ((addr->in6_16[5] == 0xffff) || (addr->in6_16[5] == 0 && addr->in6_16[6] != 0))
- return (ntohs(addr->in6_16[6]) & 0xff00) == 0x7f00;
- else
- return addr->in6_16[5] == 0 && addr->in6_16[6] == 0 && htons(addr->in6_16[7]) == 1;
-}
return ircd_ntoa_r(buf, in);
}
-/* This doesn't really belong here, but otherwise umkpasswd breaks. */
-/** Check whether an IP address looks like an IPv4 address.
- * @param[in] addr Address to check.
- * @return Non-zero if the address is a valid IPv4 address, zero if not.
- */
-int irc_in_addr_is_ipv4(const struct irc_in_addr *addr)
-{
- return addr->in6_16[0] == 0
- && addr->in6_16[1] == 0
- && addr->in6_16[2] == 0
- && addr->in6_16[3] == 0
- && addr->in6_16[4] == 0
- && (addr->in6_16[5] == 0 || addr->in6_16[5] == 0xffff)
- && addr->in6_16[6] != 0;
-}
-
/** Convert an IP address to printable ASCII form.
* @param[out] buf Output buffer to write to.
* @param[in] in Address to format.
if (ii < 7)
APPEND(':');
}
- if (max_zeros + max_start == 8)
- APPEND(':');
#undef APPEND
/* Nul terminate and return number of characters used. */
case '.': {
uint32_t ip4;
unsigned int len;
- len = ircd_aton_ip4(input + pos, &ip4);
+ len = ircd_aton_ip4(part_start, &ip4);
if (!len || (ii > 6))
return 0;
ip->in6_16[ii++] = htons(ntohl(ip4) >> 16);
ip->in6_16[ii++] = htons(ntohl(ip4) & 65535);
- pos += len;
- break;
+ if (colon < 8) {
+ unsigned int jj;
+ /* Shift stuff after "::" up and fill middle with zeros. */
+ for (jj = 0; jj < ii - colon; jj++)
+ ip->in6_16[7 - jj] = ip->in6_16[ii - jj - 1];
+ for (jj = 0; jj < 8 - ii; jj++)
+ ip->in6_16[colon + jj] = 0;
+ }
+ return part_start - input + len;
}
default: {
- unsigned int jj;
- if (colon >= 8)
- return 0;
- /* Shift stuff after "::" up and fill middle with zeros. */
ip->in6_16[ii++] = htons(part);
- for (jj = 0; jj < ii - colon; jj++)
- ip->in6_16[7 - jj] = ip->in6_16[ii - jj - 1];
- for (jj = 0; jj < 8 - ii; jj++)
- ip->in6_16[colon + jj] = 0;
+ if (colon < 8) {
+ unsigned int jj;
+ /* Shift stuff after "::" up and fill middle with zeros. */
+ for (jj = 0; jj < ii - colon; jj++)
+ ip->in6_16[7 - jj] = ip->in6_16[ii - jj - 1];
+ for (jj = 0; jj < 8 - ii; jj++)
+ ip->in6_16[colon + jj] = 0;
+ }
return pos;
}
}
+++ /dev/null
-
-CPPFLAGS = -I../../include -I../../config
-CFLAGS = -g -Wall
-
-TESTPROGS = \
- ircd_chattr_t \
- ircd_string_t
-
-all: ${TESTPROGS}
-
-ircd_chattr_t: ircd_chattr_t.o ../ircd_string.o
- ${CC} -o $@ $^
-
-ircd_string_t: ircd_string_t.o ../ircd_string.o
- ${CC} -o $@ $^
-
-.PHONY: clean
-
-clean:
- rm -f core *.o ${TESTPROGS}
--- /dev/null
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+CPPFLAGS = -I$(top_srcdir)/include -I../..
+CFLAGS = -g -Wall
+
+TESTPROGS = \
+ ircd_chattr_t \
+ ircd_string_t \
+ ircd_in_addr_t
+
+all: ${TESTPROGS}
+
+ircd_chattr_t: ircd_chattr_t.o test_stub.o ../ircd_string.o
+ ${CC} -o $@ $^
+
+ircd_string_t: ircd_string_t.o test_stub.o ../ircd_string.o
+ ${CC} -o $@ $^
+
+ircd_in_addr_t: ircd_in_addr_t.o test_stub.o ../ircd_alloc.o ../ircd_string.o ../match.o ../numnicks.o
+ $(CC) -o $@ $^
+
+.PHONY: clean
+
+clean:
+ rm -f core *.o ${TESTPROGS}
--- /dev/null
+/* ircd_in_addr_t.c - Test file for IP address manipulation */
+
+#include "ircd_log.h"
+#include "ircd_string.h"
+#include "numnicks.h"
+#include "res.h"
+#include <stdio.h>
+#include <string.h>
+#include <netinet/in.h>
+
+/** Structure to describe a test for IP address parsing and unparsing. */
+struct address_test {
+ const char *text; /**< Textual address to parse. */
+ const char *canonical; /**< Canonical form of address. */
+ struct irc_in_addr expected; /**< Parsed address. */
+ const char *base64_v4; /**< v4-only compatible base64 encoding. */
+ const char *base64_v6; /**< v6-compatible base64 encoding. */
+ unsigned int is_valid : 1; /**< is address valid? */
+ unsigned int is_ipv4 : 1; /**< is address ipv4? */
+ unsigned int is_loopback : 1; /**< is address loopback? */
+};
+
+/** Array of addresses to test with. */
+static struct address_test test_addrs[] = {
+ { "::", "0::",
+ {{ 0, 0, 0, 0, 0, 0, 0, 0 }},
+ "AAAAAA", "_", 0, 0, 0 },
+ { "::1", "0::1",
+ {{ 0, 0, 0, 0, 0, 0, 0, 1 }},
+ "AAAAAA", "_AAB", 1, 0, 1 },
+ { "127.0.0.1", "127.0.0.1",
+ {{ 0, 0, 0, 0, 0, 0, 0x7f00, 1 }},
+ "B]AAAB", "B]AAAB", 1, 1, 1 },
+ { "::ffff:127.0.0.3", "127.0.0.3",
+ {{ 0, 0, 0, 0, 0, 0xffff, 0x7f00, 3 }},
+ "B]AAAD", "B]AAAD", 1, 1, 1 },
+ { "2002:7f00:3::1", "2002:7f00:3::1",
+ {{ 0x2002, 0x7f00, 3, 0, 0, 0, 0, 1 }},
+ "B]AAAD", "CACH8AAAD_AAB", 1, 0, 0 },
+ { "8352:0344:0:0:0:0:2001:1204", "8352:344::2001:1204",
+ {{ 0x8352, 0x344, 0, 0, 0, 0, 0x2001, 0x1204 }},
+ "AAAAAA", "INSANE_CABBIE", 1, 0, 0 },
+ { 0 },
+};
+
+/** Perform tests for a single IP address.
+ * @param[in] addr Address test structure.
+ */
+static void
+test_address(struct address_test *addr)
+{
+ struct irc_in_addr parsed;
+ unsigned int ii, len, val;
+ char unparsed[64], base64_v4[64], base64_v6[64];
+
+ /* Convert expected address to network order. */
+ for (ii = 0; ii < 8; ++ii)
+ addr->expected.in6_16[ii] = htons(addr->expected.in6_16[ii]);
+ /* Make sure the text form is parsed as expected. */
+ len = ircd_aton(&parsed, addr->text);
+ assert(len == strlen(addr->text));
+ assert(!irc_in_addr_cmp(&parsed, &addr->expected));
+ /* Make sure it converts back to ASCII. */
+ ircd_ntoa_r(unparsed, &parsed);
+ assert(!strcmp(unparsed, addr->canonical));
+ /* Check IP-to-base64 conversion. */
+ iptobase64(base64_v4, &parsed, sizeof(base64_v4), 0);
+ iptobase64(base64_v6, &parsed, sizeof(base64_v6), 1);
+ if (addr->base64_v4)
+ assert(!strcmp(base64_v4, addr->base64_v4));
+ if (addr->base64_v6)
+ assert(!strcmp(base64_v6, addr->base64_v6));
+ /* Check testable attributes. */
+ val = irc_in_addr_valid(&parsed);
+ assert(!!val == addr->is_valid);
+ val = irc_in_addr_is_ipv4(&parsed);
+ assert(!!val == addr->is_ipv4);
+ val = irc_in_addr_is_loopback(&parsed);
+ assert(!!val == addr->is_loopback);
+ printf("Passed: %s (%s/%s)\n", addr->text, base64_v4, base64_v6);
+}
+
+int
+main(int argc, char *argv[])
+{
+ unsigned int ii;
+
+ for (ii = 0; test_addrs[ii].text; ++ii)
+ test_address(&test_addrs[ii]);
+
+ return 0;
+}
--- /dev/null
+/* test_stub.c - support stubs for test programs */
+
+#include "client.h"
+#include "ircd_log.h"
+#include "s_debug.h"
+#include <stdarg.h>
+#include <stdio.h>
+
+struct Client me;
+int log_inassert;
+
+void
+log_write(enum LogSys subsys, enum LogLevel severity, unsigned int flags,
+ const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+}
+
+void
+debug(int level, const char *form, ...)
+{
+ va_list args;
+
+ va_start(args, form);
+ vfprintf(stdout, form, args);
+ va_end(args);
+}
+
+int
+exit_client(struct Client *cptr, struct Client *bcptr, struct Client *sptr,
+ const char *comment)
+{
+ Debug((DEBUG_LIST, "exit_client(%p, %p, %p, \"%s\")\n", cptr, bcptr, sptr, comment));
+ return 0;
+}