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, ×truct); + + 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