[pisa-src] r2512 - in trunk: Makefile.am tools/dhcp tools/dhcp/README tools/dhcp/mac2ip.c tools/dhcp/mac2ip.h

  • From: Christoph Viethen <christoph.viethen@xxxxxxxxxxxxxx>
  • To: pisa-src@xxxxxxxxxxxxx
  • Date: Tue, 5 Apr 2011 00:20:16 +0200

Author: viethen
Date: Tue Apr  5 00:20:14 2011
New Revision: 2512

Log:
add directory for PiSA-specific DHCP code development (ensuring dist.
tarball completeness); dir initially contains the original MAC2IP code
fragments by Max Gelmroth, subject to review and possibly bugfixing

Added:
   trunk/tools/dhcp/
   trunk/tools/dhcp/README
   trunk/tools/dhcp/mac2ip.c
   trunk/tools/dhcp/mac2ip.h
Modified:
   trunk/Makefile.am

Modified: trunk/Makefile.am
==============================================================================
--- trunk/Makefile.am   Mon Apr  4 15:16:37 2011        (r2511)
+++ trunk/Makefile.am   Tue Apr  5 00:20:14 2011        (r2512)
@@ -38,6 +38,7 @@
              pairing/defaults                   \
              pairing/pisaum                     \
              tools/convenience-scripts          \
+             tools/dhcp                         \
              tools/live-cds                     \
              tools/packaging                    \
              tools/screenrc                     \

Added: trunk/tools/dhcp/README
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ trunk/tools/dhcp/README     Tue Apr  5 00:20:14 2011        (r2512)
@@ -0,0 +1,82 @@
+tools/dhcp subdirectory: PiSA-/MobileACcess-specific DHCP
+
+Background
+==========
+Upon first contact with a Host Access Point, a Mobile Guest
+needs to be assigned an IPv4 address through DHCP. We're
+talking about the most basic, i.e. lowest-layer IP address:
+It will be used on the lowest network layer (below any tunnels)
+ - the layer that's needed for native clients (mobile guests) to
+get through to their respective Trust Point. (Layered on top
+of this layer, counting upwards, there will be UDP, HIP and
+PISA, adding additional identifiers or IP addresses which
+we'll completely disregard here.)
+
+(For legacy clients, this lowest-layer IP address will at
+least allow them some access to local services, details of
+which are beyond the scope of this README file.)
+
+
+Problem
+=======
+Since the IP that a Mobile Guest uses needs to be the same
+across all Host APs (the mobile station may be on the move),
+and since we don't want to exchange state between Host APs,
+we need to be able to statelessly assign the same IP address
+across all Host APs.
+
+(Note also that we cannot reliably predict at what times the
+mobile guest may ask for an IP address through DHCP - maybe the
+user puts the machine to sleep and "wakes" it at some other
+Host AP, causing it to ask that AP for an IP address even
+before its previous DHCP lease would have expired. In all such
+cases, we need to ensure consistent IP assignment.)
+
+
+Solution
+========
+Our way to achieve this is to calculate the IP that will be
+assigned based upon the hardware address ("MAC address") of
+the mobile station.
+
+The "MAC2IP" code does this calculation. We supply patches
+to common DHCP servers (ISC dhcpd versions 3.1.3 and 4.1.1-P1,
+potentially dnsmasq) to make them use the MAC2IP logic.
+
+
+List of files
+=============
+README         this file
+
+mac2ip.c       MAC2IP code, originally by Max Gelmroth
+mac2ip.h
+
+
+Additional background info, thoughts, open ends, etc.
+=====================================================
+What if our MAC2IP algorithm gives the same IP address
+for two different mobile stations? (Introduction of "day
+of year" to modify the hash algorithm, so collisions can
+be not just spacially but also temporally distributed.)
+
+(Note that this problem only affects mobile guests using
+one and the same specific Host AP - behind the Host AP,
+before the traffic gets transported onwards towards a mobile
+guest's Trust Point, there's a NAT (Network Address
+Translation) step that will cause separation of address
+spaces and mitigate the collision problem.)
+
+The IP address that the MAC2IP algorithm calculates will
+have to be within the range of allowed IP addresses that
+we want to assign, which accordingly is configurable.
+(E.g.: "only assign IP addresses within 10.0.0.0/8")
+Obviously, this configured range will need to be the same
+across the set of all Host APs within which the roaming of
+mobile stations is supposed to work.
+
+
+To be continued.
+
+
+C. Viethen, April 2011
+

Added: trunk/tools/dhcp/mac2ip.c
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ trunk/tools/dhcp/mac2ip.c   Tue Apr  5 00:20:14 2011        (r2512)
@@ -0,0 +1,276 @@
+/**
+ * This Code calculates IPv4s based on Ethernet-addresses
+ *
+ * Author:     Max Gelmroth
+ *
+ */
+
+#include "mac2ip.h"
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <time.h>
+#include <stdio.h>
+
+//mac2ip.conf file
+const char *CONFIG_FILE_LOCATION = "/etc/mac2ip.conf";
+
+
+/*******************************************************************************
+ *                                                     HASH ALGORITHM
+ 
*******************************************************************************/
+
+
+//Jenkins one-at-a-time hash (see http://burtleburtle.net/bob/hash/doobs.html)
+uint32_t jenkins_one_at_a_time_hash(const unsigned char *key, const size_t 
key_len) {
+       uint32_t hash = 0;
+       size_t i;
+
+       for (i = 0; i < key_len; i++) {
+               hash += key[i];
+               hash += (hash << 10);
+               hash ^= (hash >> 6);
+       }
+       hash += (hash << 3);
+       hash ^= (hash >> 11);
+       hash += (hash << 15);
+       return hash;
+}
+
+
+//hash mac random ip
+void hash_mac_to_rnd_ip_OAAT(const mac2ip_mac_t *mac, mac2ip_ipv4_t *ip){
+       const uint8_t uint8_max_value = 255, max_string_len = 32;
+       time_t cur_time;
+       struct tm timestruct;
+       uint32_t hash;
+       mac2ip_mac_t mac_duplicate;
+
+       memcpy(&mac_duplicate, mac, sizeof(mac_duplicate));
+       
+       /*
+        * use day of the year in the hashfunction to avoid
+        * that two MAC-addresses that are hashed to the same
+        * IP today causes a collision tomorrow, too.
+        */
+       cur_time = time(NULL);
+       gmtime_r(&cur_time, &timestruct);
+
+       mac_duplicate.x[3] = (mac_duplicate.x[3] + timestruct.tm_yday + 1) % 
(uint8_max_value + 1);
+
+       //hash it!
+       hash = jenkins_one_at_a_time_hash((char *)mac_duplicate.x, 
sizeof(mac_duplicate.x));
+
+       *((uint32_t*)ip->x) = hash;
+
+}
+
+
+//converts mac in hex_string_format to mac_t
+static void string_to_ipv4_t(const char *string, mac2ip_ipv4_t *ip) {
+       int i;
+       char *byte = NULL, *string_duplicate = NULL;
+
+       string_duplicate = strdup(string);
+
+
+       byte = strtok(string_duplicate, ".");
+
+       for (i=0; i < sizeof(ip->x); i++) {
+
+               sscanf(byte, "%hhu", &ip->x[i]);
+
+               byte = strtok(NULL, ".");
+
+       }
+
+       free(string_duplicate);
+}
+
+
+static char *readline(FILE * fp, char **buf, size_t *buflen) {
+       char *newline = NULL;
+       char *p;
+       char *line;                                     /* The array that 
contains everything that has been read so far */
+       char *idx;                                      /* Read into this 
pointer, which points to an offset within line */
+       size_t size, newsize;           /* The size of the current array 
pointed to by line */
+       size_t maxlen;                          /* Maximum number of characters 
that may be read with fgets.  This is newsize - oldsize. */
+
+       if(feof(fp))
+               return NULL;
+
+       if(buf && buflen) {
+               size = *buflen;
+               line = *buf;
+       } else {
+               size = 100;
+               line = malloc(size);
+       }
+
+       maxlen = size;
+       idx = line;
+       *idx = 0;
+
+       for(;;) {
+               p = fgets(idx, maxlen, fp);
+
+               if(!p) {                                /* EOF or error */
+                       if(feof(fp))
+                               break;
+
+                       /* otherwise: error; let the calling function print an 
error message if applicable */
+                       free(line);
+                       return NULL;
+               }
+
+               newline = strchr(p, '\n');
+
+               if(!newline) {                  /* We haven't yet read 
everything to the end of the line */
+                       newsize = size << 1;
+                       line = realloc(line, newsize);
+                       idx = &line[size - 1];
+                       maxlen = newsize - size + 1;
+                       size = newsize;
+               } else {
+                       *newline = '\0';        /* kill newline */
+                       if(newline > p && newline[-1] == '\r')  /* and carriage 
return if necessary */
+                               newline[-1] = '\0';
+                       break;                          /* yay */
+               }
+       }
+
+       if(buf && buflen) {
+               *buflen = size;
+               *buf = line;
+       }
+
+       return line;
+}
+
+
+/* Read IP-bounds from file
+ * return -1 if an error occured
+ * otherwise it returns the number of
+ * IPs that have been read
+ */
+int read_ip_bounds(ip_bounds *bounds) {
+       int retval = 0;
+       FILE *fp = NULL;
+       char *buffer = NULL, *line = NULL;
+       char *variable = NULL, *value = NULL, *eol = NULL;
+       int len;
+       size_t buffsize = 100;
+
+       fp = fopen(CONFIG_FILE_LOCATION, "r");
+
+       if(!fp) {
+               return -1;
+       }
+
+       buffer = malloc(buffsize);
+
+       for (;;) {
+
+               if(feof(fp)) {
+                       retval = -1;
+                       printf("cannot open file %s to read IPs from!\n", 
CONFIG_FILE_LOCATION);
+                       break;
+               }
+
+               line = readline(fp, &buffer, &buffsize);
+
+               if(!line) {
+                       retval = -1;
+                       break;
+               }
+
+               variable = value = line;
+
+               if (strcmp(line, "\n") == 0)
+                       continue;
+
+               eol = line + strlen(line);
+               while(strchr("\t ", *--eol))
+                       *eol = '\0';
+
+               len = strcspn(value, "\t =");
+               value += len;
+               value += strspn(value, "\t ");
+               if(*value == '=') {
+                       value++;
+                       value += strspn(value, "\t ");
+               }
+               variable[len] = '\0';
+
+
+               if(!*value)
+                       continue;
+
+
+               if (strcmp(variable, "lower_client_ip_bound") == 0) {
+                       string_to_ipv4_t(value, &bounds->bound[0]);
+                       retval++;
+                       continue;
+               }
+
+               if (strcmp(variable, "upper_client_ip_bound") == 0) {
+                       string_to_ipv4_t(value, &bounds->bound[1]);
+                       retval++;
+                       continue;
+               }
+
+               if (strcmp(variable, "lower_service_ip_bound") == 0) {
+                       string_to_ipv4_t(value, &bounds->bound[2]);
+                       retval++;
+                       continue;
+               }
+
+               if (strcmp(variable, "upper_service_ip_bound") == 0) {
+                       string_to_ipv4_t(value, &bounds->bound[3]);
+                       retval++;
+               }
+
+       }
+
+       fclose(fp);
+       free(buffer);
+
+       return retval;
+
+}
+
+
+//adjusts the ip to the given bounds
+void adjust_ip_to_bounds(mac2ip_ipv4_t *ip, const mac2ip_ipv4_t *upper_bound, 
const mac2ip_ipv4_t *lower_bound) {
+       int i, ips_byte_len = 4;
+
+
+       for (i=0; i < ips_byte_len; i++) {
+
+               //x % 0 is undefined :(
+               if (upper_bound->x[i] - lower_bound->x[i] == 0) {
+                       ip->x[i] = lower_bound->x[i];
+               } else {
+                       ip->x[i] = (ip->x[i] % (upper_bound->x[i] - 
lower_bound->x[i])) + lower_bound->x[i];
+               }
+       }
+}
+
+
+int mac_to_ip(const mac2ip_mac_t *mac, mac2ip_ipv4_t *ip) {
+       ip_bounds bounds;
+
+
+       hash_mac_to_rnd_ip_OAAT(mac, ip);
+
+       //we want to read at least 4 IPs
+       if (read_ip_bounds(&bounds) >= 2) {
+               printf("ERROR reading ip-bounds!\n");
+               return -1;
+       }
+
+       adjust_ip_to_bounds(ip, &bounds.bound[1], &bounds.bound[0]);
+
+       return 0;
+
+}

Added: trunk/tools/dhcp/mac2ip.h
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ trunk/tools/dhcp/mac2ip.h   Tue Apr  5 00:20:14 2011        (r2512)
@@ -0,0 +1,60 @@
+/**
+ * Author:     Max Gelmroth
+ *
+ * NOTE:       for mac2ip to work properly you
+ *                     need to create a mac2ip.conf file
+ *                     and store it in /etc
+ *
+ *                     by now it only has to contain two
+ *                     lines that define the ip bounds the
+ *                     hashed ip will be adjusted to
+ *
+ *                     the file should look like:
+ *                     lower_client_ip_bound=xxx.xxx.xxx.xxx
+ *                     upper_client_ip_bound=xxx.xxx.xxx.xxx
+ *             lower_service_ip_bound=xxx.xxx.xxx.xxx
+ *             upper_service_ip_bound=xxx.xxx.xxx.xxx
+ *
+ */
+
+
+#ifndef __MAC2IP_H__
+#define __MAC2IP_H__
+
+
+#include <stdint.h>
+
+
+typedef struct mac2ip_ipv4_t{
+       uint8_t x[4];
+} mac2ip_ipv4_t;
+
+typedef struct mac2ip_mac_t{
+       uint8_t x[6];
+} mac2ip_mac_t;
+
+
+typedef struct ip_bounds {
+
+       /*
+        * lower client's ip bound      := 0
+        * upper client's ip bound      := 1
+        * lower service's ip bound     := 2
+        * upper service's ip bound     := 3
+        */
+       mac2ip_ipv4_t bound[4];
+
+} ip_bounds;
+
+/*
+ * hash mac random ip that is adjusted to the ip-bounds
+ * configured in /etc/mac2ip.conf
+ * result will be stored in 'ip'
+ *
+*/
+int mac_to_ip(const mac2ip_mac_t *, mac2ip_ipv4_t *);
+
+int read_ip_bounds(ip_bounds *);
+
+
+#endif                                                 /* __MAC2IP_H__ */
-- 
This is the pisa developer mailing list. Please also subscribe to the main pisa 
list at:
//www.freelists.org/list/pisa

Other related posts: