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