[pisa-src] r2955 - in trunk: Makefile.am openwrt/package/pisa/Makefile pairing/util pairing/util/binary.c pairing/util/call-hipconf.c pairing/util/get-neighbours.c pairing/util/output.c pairing/util/parse.c p...

  • From: Christoph Viethen <christoph.viethen@xxxxxxxxxxxxxx>
  • To: pisa-src@xxxxxxxxxxxxx
  • Date: Fri, 23 Mar 2012 19:15:05 +0100

Author: viethen
Date: Fri Mar 23 19:15:04 2012
New Revision: 2955

Log:
Contribute utility which will find Pairing candidates, to be used by
the shell scripts in the webif GUI. Ensure it gets included in the
pisa-pairing OpenWrt package, and adapt the Makefile.am appropriately.

Added:
   trunk/pairing/util/binary.c
   trunk/pairing/util/call-hipconf.c
   trunk/pairing/util/get-neighbours.c
   trunk/pairing/util/output.c
   trunk/pairing/util/parse.c
   trunk/pairing/util/pisa-pairing-candidates.c
   trunk/pairing/util/pisapair.h
   trunk/pairing/util/protos.h
Modified:
   trunk/Makefile.am
   trunk/openwrt/package/pisa/Makefile
   trunk/pairing/util/   (props changed)

Modified: trunk/Makefile.am
==============================================================================
--- trunk/Makefile.am   Fri Mar 23 17:11:31 2012        (r2954)
+++ trunk/Makefile.am   Fri Mar 23 19:15:04 2012        (r2955)
@@ -4,9 +4,10 @@
 ACLOCAL_AMFLAGS  = -I m4
 
 HEADER_LIST = community-operator/server/*.h \
-              community-operator-legacy/*.h  \
+              community-operator-legacy/*.h \
               libpisa/*.h                   \
               pairing-legacy/*.h            \
+              pairing/util/*.h              \
               pisacd/*.h                    \
               pisasd/*.h
 
@@ -71,6 +72,7 @@
                pairing-legacy/passgen                    \
                pairing-legacy/send                       \
                pairing/util/pisa-cert-info               \
+               pairing/util/pisa-pairing-candidates      \
                pairing/util/pisa-pairing-date            \
                pisacd/pisacdconf                         \
                pisasd/pisasdconf                         \
@@ -150,6 +152,13 @@
 
 pairing_util_pisa_cert_info_SOURCES = pairing/util/pisa-cert-info.c
 
+pairing_util_pisa_pairing_candidates_SOURCES = pairing/util/binary.c           
       \
+                                               pairing/util/call-hipconf.c     
       \
+                                               pairing/util/get-neighbours.c   
       \
+                                               pairing/util/output.c           
       \
+                                               
pairing/util/pisa-pairing-candidates.c \
+                                               pairing/util/parse.c
+
 pairing_util_pisa_pairing_date_SOURCES = pairing/util/pisa-pairing-date.c
 
 pisabeacon_pisabeacon_SOURCES = pisabeacon/pisabeacon.c

Modified: trunk/openwrt/package/pisa/Makefile
==============================================================================
--- trunk/openwrt/package/pisa/Makefile Fri Mar 23 17:11:31 2012        (r2954)
+++ trunk/openwrt/package/pisa/Makefile Fri Mar 23 19:15:04 2012        (r2955)
@@ -123,6 +123,7 @@
        $(INSTALL_BIN) $(PKG_BUILD_DIR)/pairing/webif/mobileaccess-cand.sh 
$(1)/www/cgi-bin/webif/
        $(INSTALL_BIN) $(PKG_BUILD_DIR)/pairing/uci/update-pisasd-conf 
$(1)/usr/bin/
        $(INSTALL_BIN) $(PKG_BUILD_DIR)/pairing/util/pisa-cert-info 
$(1)/usr/bin/
+       $(INSTALL_BIN) $(PKG_BUILD_DIR)/pairing/util/pisa-pairing-candidates 
$(1)/usr/bin/
        $(INSTALL_BIN) $(PKG_BUILD_DIR)/pairing/util/pisa-pairing-date 
$(1)/usr/bin/
 endef
 

Added: trunk/pairing/util/binary.c
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ trunk/pairing/util/binary.c Fri Mar 23 19:15:04 2012        (r2955)
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 2012, Distributed Systems Group, RWTH Aachen
+ * All rights reserved.
+ */
+
+/** @file
+ *
+ * Routines for calling a binary and collecting its output for further
+ *  processing.
+ *
+ * @author Christoph Viethen <christoph.viethen@xxxxxxxxxxxxxx>
+ *
+ */
+
+#include <errno.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <wchar.h>
+
+#include "protos.h"
+
+/* error codes that call_binary_get_pipe() will return */
+#define CALL_BINARY_GET_PIPE_ERR_NONE     0
+#define CALL_BINARY_GET_PIPE_ERR_PARAM   -1
+#define CALL_BINARY_GET_PIPE_ERR_ALLOC   -2
+#define CALL_BINARY_GET_PIPE_ERR_MISC    -3
+#define CALL_BINARY_GET_PIPE_ERR_BINARY  -4
+
+/**
+ * Clean-up function - will be called whenever we leave call_binary_get_pipe()
+ * for any reason, and will clean up different things depending on how far
+ * we got back there.
+ *
+ * Currently just closes file descriptors of a pipe.
+ *
+ * @param readdes
+ * @param writedes
+ */
+static void call_binary_get_pipe_cleanup(int readdes, int writedes)
+{
+    if (readdes != -1) {
+        close(readdes);
+    }
+
+    if (writedes != -1) {
+        close(writedes);
+    }
+}
+
+/**
+ *  This function allocates a pipe and then calls up the named binary, making
+ *   sure its output ends up in that pipe. Caller must specify binary's path
+ *   name as well as a completely filled-in array of pointers to argv values
+ *   (suitable as parameter for execve()).
+ *
+ * Finally, a pointer to the pipe (which now hopefully holds the output from
+ *  the named binary) is returned in output_pipe.
+ *
+ * @param output_pipe     must point to an address suitable for storing a
+ *                         pointer to a pipe
+ * @param binary_pathname pathname of the binary to execute
+ * @param binary_argv     array of points to argv values, as passed to execve()
+ * @param read_stderr     whether to catch the output to stderr as well, or
+ *                         only that which the called binary sends to stdout
+ * @return                0 for "everything okay", or an error code < 0 in
+ *                         case of failure
+ */
+int call_binary_get_pipe(FILE **output_pipe, const char *binary_pathname, char 
*const *binary_argv, bool read_stderr)
+{
+    pid_t pid, savedpid;
+    int exec_returncode;
+    int pipedes[2];
+    int readdes = -1, writedes = -1;
+    FILE *inputstream;
+
+    /* check that we got passed some pointers */
+    if (output_pipe == NULL || binary_pathname == NULL || binary_argv == NULL) 
{
+        call_binary_get_pipe_cleanup(-1, -1);
+        return CALL_BINARY_GET_PIPE_ERR_PARAM;
+    }
+
+    /* create a pipe that will be used to get at the output of the binary */
+    if (pipe(pipedes) == -1) {
+        call_binary_get_pipe_cleanup(-1, -1);
+        return CALL_BINARY_GET_PIPE_ERR_ALLOC;
+    }
+
+    readdes  = pipedes[0];
+    writedes = pipedes[1];
+
+    /* get us a more convenient stream to access the pipe later on ... */
+    if ((inputstream = fdopen(readdes, "r")) == NULL) {
+        call_binary_get_pipe_cleanup(readdes, writedes);
+        return CALL_BINARY_GET_PIPE_ERR_ALLOC;
+    }
+
+    /* ... and let it be a byte-oriented stream */
+    fwide(inputstream, -1);
+
+    /* make OS execute the binary, fork()ing another process which will call
+     *  execve(); contrary to what system() would do internally, we don't
+     *  undertake any special kind of signal handling, such as ignoring or
+     *  catching anything: if a signal reaches us (being a cgi-bin started by
+     *  a web server) or our child process (being rather non-interactive),
+     *  something clearly went wrong, so the default signal actions (usually:
+     *  premature termination of our process(es)) should be appropriate */
+    switch (pid = fork()) {
+    case -1:                         /* fork() failed */
+        call_binary_get_pipe_cleanup(readdes, writedes);
+        return CALL_BINARY_GET_PIPE_ERR_MISC;
+    case 0:                          /* child */
+        /* redirect stdout and stderr to the "write side" of our pipe, so
+         *  all output from the binary is collected */
+        if (close(STDIN_FILENO) == 0) {
+            if (dup2(writedes, STDOUT_FILENO) != -1) {
+                if (read_stderr == false ? (close(STDERR_FILENO) == 0) : 
(dup2(writedes, STDERR_FILENO) != -1)) {
+                    if (close(writedes) == 0) {
+                        if (close(readdes) == 0) {
+                            execve(binary_pathname, binary_argv, NULL);
+                            /* if execve() works, it never returns */
+                        }
+                    }
+                }
+            }
+        }
+        /* if we get here, something must have gone wrong with the execve() or
+         *  with the preparatory steps leading up to it */
+        exit(127);
+    default:                 /* parent; just waits till child process is done 
*/
+        savedpid = pid;
+        do {
+            pid = waitpid(savedpid, &exec_returncode, WUNTRACED);
+        } while (pid == -1 && errno == EINTR);
+    }
+
+    if (pid == -1) {
+        call_binary_get_pipe_cleanup(readdes, writedes);
+        return CALL_BINARY_GET_PIPE_ERR_MISC;
+    }
+
+    /* should our child process get stopped (e.g. SIGSTOP, SIGTSTP, SIGTTIN,
+     *  SIGTTOU) for weird reasons (really shouldn't happen, since it won't
+     *  generate terminal output while being in a background process group
+     *  and won't try to get input either), we can only a) wait (potentially
+     *  forever) till it gets continued or b) just kill it off. The latter
+     *  seems like a reasonable reaction to something that "shouldn't happen"
+     *  at all. */
+    if (WIFSTOPPED(exec_returncode)) {
+        kill(savedpid, SIGKILL);
+        do {
+            pid = waitpid(savedpid, &exec_returncode, 0);
+        } while (pid == -1 && errno == EINTR);
+
+        call_binary_get_pipe_cleanup(readdes, writedes);
+        return CALL_BINARY_GET_PIPE_ERR_MISC;
+    }
+
+    /* our kid exited due to receiving a signal (should not have happened) */
+    if (WIFSIGNALED(exec_returncode)) {
+        call_binary_get_pipe_cleanup(readdes, writedes);
+        return CALL_BINARY_GET_PIPE_ERR_MISC;
+    }
+
+    if (WIFEXITED(exec_returncode)) {
+        if (WEXITSTATUS(exec_returncode) == 127) {   /* execve() didn't work */
+            call_binary_get_pipe_cleanup(readdes, writedes);
+            return CALL_BINARY_GET_PIPE_ERR_MISC;
+        }
+    }
+
+    /* clean up, not closing the "readdes" file descriptor (but do close the
+     *  "writedes" file descriptor - otherwise, the pipe may misfunction later
+     *  on, blocking instead of indicating EOF) */
+    call_binary_get_pipe_cleanup(-1, writedes);
+
+    /* return the result everybody is waiting for */
+    *output_pipe = inputstream;
+
+    if (WEXITSTATUS(exec_returncode) != EXIT_SUCCESS) {
+        return CALL_BINARY_GET_PIPE_ERR_BINARY;
+    } else {
+        return CALL_BINARY_GET_PIPE_ERR_NONE;
+    }
+}

Added: trunk/pairing/util/call-hipconf.c
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ trunk/pairing/util/call-hipconf.c   Fri Mar 23 19:15:04 2012        (r2955)
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2012, Distributed Systems Group, RWTH Aachen
+ * All rights reserved.
+ */
+
+/** @file
+ *
+ * Routines for interacting with a locally running hipd through calls
+ *  of the hipconf utility.
+ *
+ * @author Christoph Viethen <christoph.viethen@xxxxxxxxxxxxxx>
+ *
+ */
+
+#include <netinet/in.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "protos.h"
+
+/* the name and complete path to the hipconf executable (do not use relative
+ * paths here for security reasons - we'll execute as root)   */
+#define HIPCONF_NAME     "hipconf"
+#define HIPCONF_PATHNAME "/usr/sbin/" HIPCONF_NAME
+
+/* error codes that call_hipconf() will return */
+#define CALL_HIPCONF_ERR_ALLOC   -5
+#define CALL_HIPCONF_ERR_PARAM   -6
+
+/**
+ * This function will perform a number of simple checks of the params that
+ *  are supposed to be handed to hipconf.
+ *
+ * @param params
+ * @param num_params
+ * @return           0 for "everything okay", or -1 in case of error
+ */
+static int call_hipconf_check_params(char **params, const int num_params)
+{
+/*  size_t     issuer_len;
+ *  size_t     subject_len;
+ *  size_t     notbefore_len;
+ *  size_t     notafter_len;
+ *  const char allowed_in_v6addresses[]  = "0123456789ABCDEFabcdef:";
+ *  const char allowed_in_unsigned_int[] = "0123456789";
+ */
+    if (params == NULL) {
+        return -1;
+    }
+
+    if (num_params == 4 && !strcmp("daemon", params[1]) && !strcmp("get", 
params[2]) && !strcmp("hi", params[3]) && !strcmp("default", params[4])) {
+        return 0;
+    }
+
+    if (num_params == 4 && !strcmp("daemon", params[1]) && !strcmp("get", 
params[2]) && !strcmp("ha", params[3]) && !strcmp("all", params[4])) {
+        return 0;
+    }
+
+    if ((num_params == 4 || num_params == 5) && !strcmp("daemon", params[1]) 
&& !strcmp("acquire", params[2]) && !strcmp("certificate", params[3])) {
+        /* FIXME: definitely would like more checking code here */
+        return 0;
+    }
+
+    return -1;
+}
+
+/**
+ * This function makes sure the hipconf binary gets called, its output ending
+ *  up in a pipe. The variadic parameters get passed on as command-line
+ *  arguments to hipconf, after some simple argument-specific plausibility
+ *  checks.
+ *
+ * @param  output_pipe must point to an address where to store the pointer
+ *                      to the pipe to
+ * @return             0 for "everything okay", or an error code < in case
+ *                      of failure
+ */
+int call_hipconf(FILE **output_pipe, ...)
+{
+    va_list ap, ap2;
+    int param_count = 0;
+    int i, result;
+
+    va_start(ap, output_pipe);
+
+    /* determine number of parameters this function got called with */
+    va_copy(ap2, ap);
+    while (va_arg(ap2, char *) != NULL) {
+        param_count++;
+    }
+    va_end(ap2);
+
+    /* put variadic parameters into an argv array for execve()ing hipconf */
+    char **const hipconf_argv = malloc((param_count + 2) * sizeof(char *));
+
+    if (hipconf_argv == NULL) {
+        return CALL_HIPCONF_ERR_ALLOC;
+    }
+
+    /* FIXME: ugly const-correctness kludge */
+    const char *tempname = HIPCONF_NAME;
+    char *tempname2;
+    memcpy(&tempname2, &tempname, sizeof(char *));
+    hipconf_argv[0] = tempname2;
+
+    for (i = 1; i < param_count + 1; i++) {
+        hipconf_argv[i] = va_arg(ap, char *);
+    }
+    hipconf_argv[param_count + 1] = NULL;
+
+    va_end(ap);
+
+    /* make sure the output_pipe parameter we got passed actually points to
+     *  something */
+    if (output_pipe == NULL) {
+        free(hipconf_argv);
+        return CALL_HIPCONF_ERR_PARAM;
+    }
+
+    /* do some more checks on the command-line parameters for hipconf
+     *  (as found in the array we just built) */
+    if (call_hipconf_check_params(hipconf_argv, param_count) == -1) {
+        free(hipconf_argv);
+        return CALL_HIPCONF_ERR_PARAM;
+    }
+
+    /* use utility function to call the hipconf binary and obtain pipe */
+    result = call_binary_get_pipe(output_pipe, HIPCONF_PATHNAME, hipconf_argv, 
true);
+
+    free(hipconf_argv);
+
+    return result;
+}

Added: trunk/pairing/util/get-neighbours.c
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ trunk/pairing/util/get-neighbours.c Fri Mar 23 19:15:04 2012        (r2955)
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2012, Distributed Systems Group, RWTH Aachen
+ * All rights reserved.
+ */
+
+/** @file
+ *
+ * @author Christoph Viethen <christoph.viethen@xxxxxxxxxxxxxx>
+ *
+ */
+
+#include "config.h"
+
+#include <netinet/in.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "protos.h"
+
+/* error codes that get_neighbours() will return */
+#define GET_NEIGHBOURS_ERR_NONE   0
+#define GET_NEIGHBOURS_ERR_PARAM -1
+
+/* get_neighbours() calls the "ip" binary to get a list of this host's 
neighbours, which
+ *  amounts to reading out the ARP table in the IPv4 case or the ND table in 
the IPv6 case.
+ *  The family parameter indicates whether we want to see the IPv4 or the IPv6 
neighbours.
+ *  The binary is called the following way:
+ *
+ *   ip -f inet[6] neigh show nud all
+ *
+ * In case the optional "device" parameter is set (to, e.g., "eth0"), "ip" 
gets called
+ *  the following way:
+ *
+ *   ip -f inet[6] neigh show dev <device> nud all
+ *
+ * The output from this call is placed in a pipe, the stream handle of which 
is returned
+ *  through output_pipe to enable later processing/parsing.
+ */
+static int get_neighbours(FILE **output_pipe, int family, char *device)
+{
+    int         arg_offset = 0;
+    int         result;
+    const char *ip_argv[10];
+    char       *ip_argv_dest[10];
+
+    /* construct the argv array for calling "ip" */
+    ip_argv[0] = "ip";
+    ip_argv[1] = "-f";
+
+    if (family == AF_INET) {
+        ip_argv[2] = "inet";
+    } else if (family == AF_INET6) {
+        ip_argv[2] = "inet6";
+    } else {
+        return GET_NEIGHBOURS_ERR_PARAM;
+    }
+
+    ip_argv[3] = "neigh";
+    ip_argv[4] = "show";
+
+    if (device != NULL) {
+        ip_argv[5] = "dev";
+        ip_argv[6] = device;
+        arg_offset = 2;
+    }
+
+    ip_argv[5 + arg_offset] = "nud";
+    ip_argv[6 + arg_offset] = "all";
+    ip_argv[7 + arg_offset] = NULL;
+
+/*    for (int j = 0; ip_argv[j] != NULL; j++) {
+ *      printf("ip_argv[%d]=%s\n", j, ip_argv[j]);
+ *  }
+ */
+    /* copy over the contents of the one to the other pointer array */
+    /* FIXME(?): const-correctness kludge */
+    memcpy(ip_argv_dest, ip_argv, 10 * (sizeof(char *)));
+
+    /* make sure the output_pipe parameter we got passed actually points to
+     * something */
+    if (output_pipe == NULL) {
+        return GET_NEIGHBOURS_ERR_PARAM;
+    }
+
+    /* use utility function to call the "ip" binary and obtain pipe */
+    result = call_binary_get_pipe(output_pipe, IP_PATHNAME, ip_argv_dest, 
true);
+
+    return result;
+}
+
+int get_v4neighbours(FILE **output_pipe, char *device)
+{
+    return get_neighbours(output_pipe, AF_INET, device);
+}
+
+int get_v6neighbours(FILE **output_pipe, char *device)
+{
+    return get_neighbours(output_pipe, AF_INET6, device);
+}

Added: trunk/pairing/util/output.c
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ trunk/pairing/util/output.c Fri Mar 23 19:15:04 2012        (r2955)
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2012, Distributed Systems Group, RWTH Aachen
+ * All rights reserved.
+ */
+
+/** @file
+ *
+ * @author Christoph Viethen <christoph.viethen@xxxxxxxxxxxxxx>
+ *
+ */
+#include <stdbool.h>
+#include <stdio.h>
+
+#include "pisapair.h"
+#include "protos.h"
+
+static void prettyprint_hit(struct in6_addr *hit, bool with_colons)
+{
+    for (int i = 0; i < 15; i += 2) {
+        printf("%02x%02x%s", hit->s6_addr[i], hit->s6_addr[i + 1], 
(with_colons == true && i != 14) ? ":" : "");
+    }
+}
+
+static void prettyprint_hwaddr(uint8_t *hwaddr)
+{
+    printf("%02x:%02x:%02x:%02x:%02x:%02x", hwaddr[0], hwaddr[1], hwaddr[2], 
hwaddr[3], hwaddr[4], hwaddr[5]);
+}
+
+static void prettyprint_ipv4addr(struct in_addr *ipaddr)
+{
+    for (int i = 0; i < 4 ; i++) {
+        printf("%d%s", ((uint8_t *)(&ipaddr->s_addr))[i], i < 3 ? "." : "");
+    }
+}
+
+void output_candidates(struct pairing_candidate *pairing_candidates)
+{
+    struct pairing_candidate *cur_candidate = pairing_candidates;
+
+    if (pairing_candidates != NULL) {
+        // output header
+        printf("<table frame=\"border\" rules=\"rows\" 
style=\"margin-top:3ex\" border=\"2\">\n");
+        printf("  <colgroup span=\"3\" />\n");
+        printf("  <thead>\n");
+        printf("    <tr>\n");
+        printf("      <th style=\"padding-top:1ex; padding-bottom:1ex; 
text-align:center\" align=\"center\">HIT</th>\n");
+        printf("      <th style=\"padding-top:1ex; padding-bottom:1ex; 
padding-left:1em; padding-right:1em; text-align:center\" 
align=\"center\">Hardware Address</th>\n");
+        printf("      <th style=\"padding-top:1ex; padding-bottom:1ex; 
padding-left:1em; padding-right:1em; text-align:center\" align=\"center\">IP 
Address</th>\n");
+        printf("      <th style=\"padding-top:1ex; padding-bottom:1ex; 
padding-left:2em; padding-right:2em; text-align:center\" 
align=\"center\">Action</th>\n");
+        printf("    </tr>\n");
+        printf("  </thead>\n");
+        printf("  <tbody>\n");
+        // output the candidates
+        // FIXME: only output those candidates which are from the right 
interface, are local, etc.pp.
+        while (cur_candidate != NULL) {
+            printf("    <tr>\n");
+            printf("      <td style=\"padding-left:1em; padding-right:1em; 
padding-top:2ex; padding-bottom:2ex\" align=\"center\">");
+            prettyprint_hit(&cur_candidate->hit, true);
+            printf("</td>\n");
+            printf("      <td style=\"padding-left:1em; padding-right:1em; 
padding-top:2ex; padding-bottom:2ex\" align=\"center\">");
+            prettyprint_hwaddr(cur_candidate->hwaddr);
+            printf("</td>\n");
+            printf("      <td style=\"padding-left:1em; padding-right:1em; 
padding-top:2ex; padding-bottom:2ex\" align=\"center\">");
+            prettyprint_ipv4addr(&cur_candidate->ipv4);
+            printf("</td>\n");
+            printf("      <td style=\"padding-left:1em; padding-right:1em; 
padding-top:2ex; padding-bottom:2ex\" align=\"center\"><input type=\"submit\" 
name=\"pair_");
+            prettyprint_hit(&cur_candidate->hit, true);
+            printf("\" value=\"Pair ...\"/></td>\n");
+            printf("    </tr>\n");
+
+            cur_candidate = cur_candidate->next;
+        }
+
+        // output footer
+        printf("  </tbody>\n");
+        printf("</table>\n");
+    }
+}

Added: trunk/pairing/util/parse.c
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ trunk/pairing/util/parse.c  Fri Mar 23 19:15:04 2012        (r2955)
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 2012, Distributed Systems Group, RWTH Aachen
+ * All rights reserved.
+ */
+
+/** @file
+ *
+ * @author Christoph Viethen <christoph.viethen@xxxxxxxxxxxxxx>
+ *
+ */
+
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <time.h>
+
+#include "pisapair.h"
+#include "protos.h"
+
+#define WITHIN_HA_ENTRY 1
+
+#define CANDFLAG_HIT_FOUND  (1L << 0)
+#define CANDFLAG_IPV4_FOUND (1L << 1)
+#define CANDFLAG_IPV6_FOUND (1L << 2)
+#define CANDFLAG_IS_LOCAL   (1L << 3)
+
+struct pairing_candidate *get_pairing_candidates(FILE *hipconf_pipe)
+{
+    char                      linebuf[120];
+    char                      prev_linebuf[120]  = { 0 };
+    int                       state              = 0;
+    struct pairing_candidate *pairing_candidates = NULL;
+    struct pairing_candidate *cur_candidate      = NULL;
+
+    /* read out the pipe line by line */
+    while (fgets(linebuf, sizeof(linebuf), hipconf_pipe) != NULL) {
+        /* only look for entry about an established HA */
+        if (state == 0) {
+            if (prev_linebuf[0] != 0) {          /* care first for previous 
line, in case
+                                                  *  it hasn't been processed 
yet */
+                if (!strncmp(prev_linebuf, "HA is ESTABLISHED", 17)) {
+                    state         = WITHIN_HA_ENTRY;
+                    cur_candidate = calloc(1, sizeof(struct 
pairing_candidate));
+
+                    if (cur_candidate == NULL) {
+                        break;
+                    }
+                }
+                prev_linebuf[0] = 0;
+            } else {
+                if (!strncmp(linebuf, "HA is ESTABLISHED", 17)) {
+                    state         = WITHIN_HA_ENTRY;
+                    cur_candidate = calloc(1, sizeof(struct 
pairing_candidate));
+
+                    if (cur_candidate == NULL) {
+                        break;
+                    }
+                }
+                continue;
+            }
+        }
+
+        /* look only for certain lines belonging to current HA */
+        if (state == WITHIN_HA_ENTRY) {
+            int addrspan;
+
+            if (!strncmp(linebuf, "HA is", 5)) {
+                memcpy(prev_linebuf, linebuf, sizeof(prev_linebuf));
+                state = 0;
+
+                if (cur_candidate->flags == (CANDFLAG_HIT_FOUND | 
CANDFLAG_IPV4_FOUND) ||
+                    cur_candidate->flags == (CANDFLAG_HIT_FOUND | 
CANDFLAG_IPV6_FOUND)) {
+                    if (pairing_candidates == NULL) {
+                        pairing_candidates = cur_candidate;
+                    } else {
+                        struct pairing_candidate **temp;
+
+                        temp = &(pairing_candidates->next);
+                        while (*temp != NULL) {
+                            temp = &((*temp)->next);
+                        }
+
+                        *temp = cur_candidate;
+                    }
+
+                    cur_candidate = NULL;
+                } else {
+                    free(cur_candidate);
+                    cur_candidate = NULL;
+                }
+
+                continue;
+            }
+
+            if (!strncmp(linebuf, " Peer  HIT: ", 12)) {
+                /* only take the string up to the first CR or LF that we find 
*/
+                addrspan          = strcspn(linebuf, "\r\n");
+                linebuf[addrspan] = 0;
+
+                if (inet_pton(AF_INET6, linebuf + 12, &cur_candidate->hit) == 
1) {
+                    cur_candidate->flags |= CANDFLAG_HIT_FOUND;
+                }
+                continue;
+            }
+
+            if (!strncmp(linebuf, " Peer  IP: ", 11)) {
+                /* only take the string up to the first CR or LF that we find 
*/
+                addrspan          = strcspn(linebuf, "\r\n");
+                linebuf[addrspan] = 0;
+
+                if (inet_pton(AF_INET6, linebuf + 11, &cur_candidate->ipv6) == 
1) {
+                    cur_candidate->flags |= CANDFLAG_IPV6_FOUND;
+                } else if (inet_pton(AF_INET, linebuf + 11, 
&cur_candidate->ipv4) == 1) {
+                    cur_candidate->flags |= CANDFLAG_IPV4_FOUND;
+                }
+                continue;
+            }
+        }
+    }
+
+    if (cur_candidate != NULL) {
+        if (cur_candidate->flags == (CANDFLAG_HIT_FOUND | CANDFLAG_IPV4_FOUND) 
||
+            cur_candidate->flags == (CANDFLAG_HIT_FOUND | 
CANDFLAG_IPV6_FOUND)) {
+            if (pairing_candidates == NULL) {
+                pairing_candidates = cur_candidate;
+            } else {
+                struct pairing_candidate **temp;
+
+                temp = &(pairing_candidates->next);
+                while (*temp != NULL) {
+                    temp = &((*temp)->next);
+                }
+
+                *temp = cur_candidate;
+            }
+
+            cur_candidate = NULL;
+        } else {
+            free(cur_candidate);
+            cur_candidate = NULL;
+        }
+    }
+
+    return pairing_candidates;
+}
+
+/* FIXME: is void correct for the return type? could it return s.th., for ex. 
in case of error? */
+static void process_neighbours(int family, struct pairing_candidate 
*pairing_candidates, FILE *neighbours_pipe)
+{
+    char linebuf[120];  // FIXME: is this okay? more? less?
+
+    while (fgets(linebuf, sizeof(linebuf), neighbours_pipe) != NULL) {
+        char                      l3addr[50];
+        struct in_addr            ipv4_addr;
+        struct in6_addr           ipv6_addr;
+        char                      interface[20];
+        uint8_t                   l2addr[6];
+        struct pairing_candidate *temp_candidate = pairing_candidates;
+
+        sscanf(linebuf, "%s dev %s lladdr %2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx 
%*s", l3addr, interface, &l2addr[0], &l2addr[1], &l2addr[2], &l2addr[3], 
&l2addr[4], &l2addr[5]);
+        // FIXME: what about buffer sizes? and don't forget to indicate the 
buffer size in the format string! (and test behaviour of the different libcs in 
case
+        //  buffer is not large enough!
+
+        /* FIXME: evaluate the return value of sscanf! */
+
+        /* convert the layer 3 network address to binary format */
+        if (family == AF_INET) {
+            inet_pton(AF_INET, l3addr, &ipv4_addr);
+        } else if (family == AF_INET6) {
+            inet_pton(AF_INET6, l3addr, &ipv6_addr);
+        }
+
+        /* FIXME: what if inet_pton() returns an error? */
+
+        if (family == AF_INET) {
+            do {
+                if ((temp_candidate->flags & CANDFLAG_IPV4_FOUND) && 
(temp_candidate->ipv4.s_addr == ipv4_addr.s_addr)) {
+                    memcpy(temp_candidate->hwaddr, l2addr, 6);
+                    temp_candidate->flags |= CANDFLAG_IS_LOCAL;
+                }
+
+                temp_candidate = temp_candidate->next;
+            } while (temp_candidate != NULL);
+        }
+        if (family == AF_INET6) {
+            do {
+                if ((temp_candidate->flags & CANDFLAG_IPV6_FOUND) && 
(memcmp(temp_candidate->ipv6.s6_addr, ipv6_addr.s6_addr, 16) == 0)) {
+                    memcpy(temp_candidate->hwaddr, l2addr, 6);
+                    temp_candidate->flags |= CANDFLAG_IS_LOCAL;
+                }
+
+                temp_candidate = temp_candidate->next;
+            } while (temp_candidate != NULL);
+        }
+    }
+}
+
+/* FIXME: is void correct for the return type? could it return s.th., for ex. 
in case of error? */
+void process_v4_neighbours(struct pairing_candidate *pairing_candidates, FILE 
*v4neighbours_pipe)
+{
+    return process_neighbours(AF_INET, pairing_candidates, v4neighbours_pipe);
+}
+
+void process_v6_neighbours(struct pairing_candidate *pairing_candidates, FILE 
*v6neighbours_pipe)
+{
+    return process_neighbours(AF_INET6, pairing_candidates, v6neighbours_pipe);
+}

Added: trunk/pairing/util/pisa-pairing-candidates.c
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ trunk/pairing/util/pisa-pairing-candidates.c        Fri Mar 23 19:15:04 
2012        (r2955)
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2012, Distributed Systems Group, RWTH Aachen
+ * All rights reserved.
+ */
+
+/** @file
+ *
+ * @author Christoph Viethen <christoph.viethen@xxxxxxxxxxxxxx>
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "pisapair.h"
+#include "protos.h"
+
+int main(void)
+{
+    int                       retcode;
+    FILE                     *hipconf_pipe       = NULL;
+    FILE                     *v4neighbours_pipe  = NULL;
+    FILE                     *v6neighbours_pipe  = NULL;
+    struct pairing_candidate *pairing_candidates = NULL;
+
+    /* ask hipconf to return the list of all host associations */
+    if ((retcode = call_hipconf(&hipconf_pipe, "daemon", "get", "ha", "all", 
(char *) NULL)) < 0) {
+        // FIXME: improve error handling here
+        printf("call_hipconf returned: %d\n", retcode);
+        return EXIT_FAILURE;
+    }
+
+    /* use "ip -f inet neigh" to get a list of all IPv4 neighbours (ARP table) 
*/
+    if ((retcode = get_v4neighbours(&v4neighbours_pipe, NULL)) < 0) {
+        printf("get_v4neighbours returned: %d\n", retcode);
+        return EXIT_FAILURE;
+    }
+
+    /* use "ip -f inet6 neigh" to get a list of all IPv6 neighbours (IPv6 ND) 
*/
+    if ((retcode = get_v6neighbours(&v6neighbours_pipe, NULL)) < 0) {
+        printf("get_v6neighbours returned: %d\n", retcode);
+        return EXIT_FAILURE;
+    }
+    // FIXME: what about closing the pipes in case of error?
+
+    /* this will turn the output from hipconf into a list of pairing 
candidates */
+    pairing_candidates = get_pairing_candidates(hipconf_pipe);
+
+    // FIXME: do we still need the hipconf_pipe here? if not, free it
+
+    // FIXME: what about freeing the list of pairing candidates (at some 
point)?
+
+    // FIXME: make sure you actually have a list of pairing candidates before 
you try
+    //  to process anything
+
+    if (pairing_candidates != NULL) {
+        // look through lists of neighbours and enter the information in the 
pairing
+        //  candidates list
+        process_v4_neighbours(pairing_candidates, v4neighbours_pipe);
+        process_v6_neighbours(pairing_candidates, v6neighbours_pipe);
+
+        // FIXME: free the other pipes now
+
+        // display the pairing candidates in the form of an HTML table
+        output_candidates(pairing_candidates);
+    }
+    return EXIT_SUCCESS;
+}

Added: trunk/pairing/util/pisapair.h
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ trunk/pairing/util/pisapair.h       Fri Mar 23 19:15:04 2012        (r2955)
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2012, Distributed Systems Group, RWTH Aachen
+ * All rights reserved.
+ */
+
+/** @file
+ *
+ * @author Christoph Viethen <christoph.viethen@xxxxxxxxxxxxxx>
+ *
+ */
+
+#ifndef _PISAPAIR_H
+#define _PISAPAIR_H 1
+
+#include <netinet/in.h>
+#include <stdio.h>
+
+struct pairing_candidate {
+    struct in6_addr           hit;
+    struct in6_addr           ipv6;
+    struct in_addr            ipv4;
+    int                       flags;
+    uint8_t                   hwaddr[6];
+    char                      ifname[20];
+    struct pairing_candidate *next;
+};
+/*
+ * struct neighbour_entry {
+ *  struct in_addr          l3addr;
+ *  char                   *device;
+ *  uint8_t                 hwaddr[6];
+ *  struct neighbour_entry *next;
+ * };
+ */
+
+#endif

Added: trunk/pairing/util/protos.h
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ trunk/pairing/util/protos.h Fri Mar 23 19:15:04 2012        (r2955)
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2012, Distributed Systems Group, RWTH Aachen
+ * All rights reserved.
+ */
+
+/** @file
+ *
+ * @author Christoph Viethen <christoph.viethen@xxxxxxxxxxxxxx>
+ *
+ */
+
+#ifndef _PROTOS_H
+#define _PROTOS_H 1
+
+int call_binary_get_pipe(FILE **output_pipe, const char *binary_pathname, char 
*const *binary_argv, _Bool read_stderr);
+int call_hipconf(FILE **output_pipe, ...);
+int get_v4neighbours(FILE **, char *);
+int get_v6neighbours(FILE **, char *);
+struct pairing_candidate *get_pairing_candidates(FILE *);
+void process_v4_neighbours(struct pairing_candidate *pairing_candidates, FILE 
*v4neighbours_pipe);
+void process_v6_neighbours(struct pairing_candidate *pairing_candidates, FILE 
*v6neighbours_pipe);
+void output_candidates(struct pairing_candidate *pairing_candidates);
+
+#endif
-- 
This is the pisa developer mailing list. Please also subscribe to the main pisa 
list at:
//www.freelists.org/list/pisa

Other related posts: