On Fri, Mar 21, 2014 at 7:23 PM, Umut Tezduyar Lindskog <umut.tezdu...@axis.com> wrote: > --- > TODO | 1 - > src/libsystemd-network/sd-ipv4ll.c | 93 > +++++++++++++++++++++++++++--------- > src/network/networkd-link.c | 12 +++++ > src/network/networkd.h | 1 + > src/shared/net-util.c | 37 ++++++++++++++ > src/shared/net-util.h | 2 + > src/shared/siphash24.h | 2 + > src/systemd/sd-ipv4ll.h | 1 + > src/udev/net/link-config.c | 27 +---------- > 9 files changed, 127 insertions(+), 49 deletions(-) > > diff --git a/TODO b/TODO > index 50d67f7..b894e23 100644 > --- a/TODO > +++ b/TODO > @@ -660,7 +660,6 @@ Features: > - add reduced [Link] support to .network files > - add IPv4LL tests (inspire by DHCP) > - add Scope= parsing option for [Network] > - - change LL address generation and make it predictable like get_mac() > (link-config.c) > - have smooth transition from LL to routable address, without > disconnecting clients. > > * sd-network: > diff --git a/src/libsystemd-network/sd-ipv4ll.c > b/src/libsystemd-network/sd-ipv4ll.c > index 689dce9..155c315 100644 > --- a/src/libsystemd-network/sd-ipv4ll.c > +++ b/src/libsystemd-network/sd-ipv4ll.c > @@ -24,6 +24,7 @@ > #include <arpa/inet.h> > > #include "util.h" > +#include "siphash24.h" > #include "list.h" > > #include "ipv4ll-internal.h" > @@ -76,6 +77,8 @@ struct sd_ipv4ll { > usec_t defend_window; > int next_wakeup_valid; > be32_t address; > + struct random_data *random_data; > + char *random_data_state; > /* External */ > be32_t claimed_address; > struct ether_addr mac_addr; > @@ -128,30 +131,27 @@ static int ipv4ll_stop(sd_ipv4ll *ll, int event) { > return 0; > } > > -static be32_t ipv4ll_pick_address(sd_ipv4ll *ll) { > +static int ipv4ll_pick_address(sd_ipv4ll *ll, be32_t *address) { > be32_t addr; > + int r; > + int32_t random; > > assert(ll); > + assert(address); > + assert(ll->random_data); > > - if (ll->address) { > - do { > - uint32_t r = random_u32() & 0x0000FFFF; > - addr = htonl(IPV4LL_NETWORK | r); > - } while (addr == ll->address || > - (ntohl(addr) & IPV4LL_NETMASK) != IPV4LL_NETWORK || > - (ntohl(addr) & 0x0000FF00) == 0x0000 || > - (ntohl(addr) & 0x0000FF00) == 0xFF00); > - } else { > - uint32_t a = 1; > - int i; > - > - for (i = 0; i < ETH_ALEN; i++) > - a += ll->mac_addr.ether_addr_octet[i]*i; > - a = (a % 0xFE00) + 0x0100; > - addr = htonl(IPV4LL_NETWORK | (uint32_t) a); > - } > + do { > + r = random_r(ll->random_data, &random); > + if (r < 0) > + return r; > + addr = htonl((random & 0x0000FFFF) | IPV4LL_NETWORK); > + } while (addr == ll->address || > + (ntohl(addr) & IPV4LL_NETMASK) != IPV4LL_NETWORK || > + (ntohl(addr) & 0x0000FF00) == 0x0000 || > + (ntohl(addr) & 0x0000FF00) == 0xFF00); > > - return addr; > + *address = addr; > + return 0; > } > > static int ipv4ll_timer(sd_event_source *s, uint64_t usec, void *userdata) { > @@ -304,7 +304,9 @@ static void ipv4ll_run_state_machine(sd_ipv4ll *ll, > IPv4LLTrigger trigger, void > ll->claimed_address = 0; > > /* Pick a new address */ > - ll->address = ipv4ll_pick_address(ll); > + r = ipv4ll_pick_address(ll, &ll->address); > + if (r < 0) > + goto out; > ll->conflict++; > ll->defend_window = 0; > ipv4ll_set_state(ll, IPV4LL_STATE_WAITING_PROBE, 1); > @@ -433,6 +435,36 @@ int sd_ipv4ll_get_address(sd_ipv4ll *ll, struct in_addr > *address){ > return 0; > } > > +int sd_ipv4ll_set_address_seed (sd_ipv4ll *ll, uint64_t entropy) { > + int r; > + > + assert_return(ll, -EINVAL); > + > + free(ll->random_data); > + free(ll->random_data_state); > + > + ll->random_data = new0(struct random_data, 1); > + ll->random_data_state = new0(char, 128); > + > + if (!ll->random_data || !ll->random_data_state) { > + r = -ENOMEM; > + goto error; > + } > + > + r = initstate_r((unsigned int)entropy, ll->random_data_state, 128, > ll->random_data); > + if (r < 0) > + goto error; > + > +error: > + if (r < 0){ > + free(ll->random_data); > + free(ll->random_data_state); > + ll->random_data = NULL; > + ll->random_data_state = NULL; > + } > + return r; > +} > + > int sd_ipv4ll_start (sd_ipv4ll *ll) { > int r; > > @@ -451,8 +483,23 @@ int sd_ipv4ll_start (sd_ipv4ll *ll) { > ll->defend_window = 0; > ll->claimed_address = 0; > > - if (ll->address == 0) > - ll->address = ipv4ll_pick_address(ll); > + if (!ll->random_data) { > + uint64_t seed; > + > + /* Fallback to mac */ > + siphash24((uint8_t*) &seed, &ll->mac_addr.ether_addr_octet, > + ETH_ALEN, HASH_KEY.bytes); > + > + r = sd_ipv4ll_set_address_seed(ll, seed); > + if (r < 0) > + goto out; > + } > + > + if (ll->address == 0) { > + r = ipv4ll_pick_address(ll, &ll->address); > + if (r < 0) > + goto out; > + } > > ipv4ll_set_state (ll, IPV4LL_STATE_INIT, 1); > > @@ -491,6 +538,8 @@ void sd_ipv4ll_free (sd_ipv4ll *ll) { > sd_ipv4ll_stop(ll); > sd_ipv4ll_detach_event(ll); > > + free(ll->random_data); > + free(ll->random_data_state); > free(ll); > } > > diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c > index a7ba466..3131671 100644 > --- a/src/network/networkd-link.c > +++ b/src/network/networkd-link.c > @@ -63,6 +63,8 @@ int link_new(Manager *manager, struct udev_device *device, > Link **ret) { > if (r < 0) > return r; > > + link->udev_device = udev_device_ref(device); > + > *ret = link; > link = NULL; > > @@ -85,6 +87,8 @@ void link_free(Link *link) { > free(link->ifname); > free(link->state_file); > > + udev_device_unref(link->udev_device); > + > free(link); > } > > @@ -1258,10 +1262,18 @@ int link_add(Manager *m, struct udev_device *device, > Link **ret) { > return r; > > if (link->network->ipv4ll) { > + uint64_t seed; > r = sd_ipv4ll_new(&link->ipv4ll); > if (r < 0) > return r; > > + r = net_get_unique_predictable_data(link->udev_device, > &seed); > + if (r >= 0) { > + r = sd_ipv4ll_set_address_seed(link->ipv4ll, seed); > + if (r < 0) > + return r; > + } > + > r = sd_ipv4ll_attach_event(link->ipv4ll, NULL, 0); > if (r < 0) > return r; > diff --git a/src/network/networkd.h b/src/network/networkd.h > index 311350c..239ef1c 100644 > --- a/src/network/networkd.h > +++ b/src/network/networkd.h > @@ -198,6 +198,7 @@ struct Link { > char *ifname; > char *state_file; > struct ether_addr mac; > + struct udev_device *udev_device; > > unsigned flags; > > diff --git a/src/shared/net-util.c b/src/shared/net-util.c > index 50cfa2c..a788a78 100644 > --- a/src/shared/net-util.c > +++ b/src/shared/net-util.c > @@ -24,6 +24,9 @@ > #include <arpa/inet.h> > #include <fnmatch.h> > > +#include "strv.h" > +#include "siphash24.h" > +#include "libudev-private.h" > #include "net-util.h" > #include "log.h" > #include "utf8.h" > @@ -31,6 +34,40 @@ > #include "conf-parser.h" > #include "condition.h" > > +int net_get_unique_predictable_data(struct udev_device *device, uint64_t > *result) { > + size_t l, sz = 0; > + const char *name, *field = NULL; > + int r; > + uint8_t *v; > + > + /* fetch some persistent data unique (on this machine) to this > device */ > + FOREACH_STRING(field, "ID_NET_NAME_ONBOARD", "ID_NET_NAME_SLOT", > "ID_NET_NAME_PATH", "ID_NET_NAME_MAC") { > + name = udev_device_get_property_value(device, field); > + if (name) > + break; > + } > + > + if (!name) > + return -ENOENT; > + > + l = strlen(name); > + sz = sizeof(sd_id128_t) + l; > + v = alloca(sz); > + > + /* fetch some persistent data unique to this machine */ > + r = sd_id128_get_machine((sd_id128_t*) v); > + if (r < 0) > + return r; > + memcpy(v + sizeof(sd_id128_t), name, l); > + > + /* Let's hash the machine ID plus the device name. We > + * use a fixed, but originally randomly created hash > + * key here. */ > + siphash24(result, v, sz, HASH_KEY.bytes); > + > + return 0; > +} > + > bool net_match_config(const struct ether_addr *match_mac, > const char *match_path, > const char *match_driver, > diff --git a/src/shared/net-util.h b/src/shared/net-util.h > index 99479e1..01a6b72 100644 > --- a/src/shared/net-util.h > +++ b/src/shared/net-util.h > @@ -62,3 +62,5 @@ int config_parse_ifalias(const char *unit, const char > *filename, unsigned line, > int ltype, const char *rvalue, void *data, void > *userdata); > > int net_parse_inaddr(const char *address, unsigned char *family, void *dst); > + > +int net_get_unique_predictable_data(struct udev_device *device, uint64_t > *result); > diff --git a/src/shared/siphash24.h b/src/shared/siphash24.h > index 62e1168..bf9d17d 100644 > --- a/src/shared/siphash24.h > +++ b/src/shared/siphash24.h > @@ -3,4 +3,6 @@ > #include <inttypes.h> > #include <sys/types.h> > > +#define HASH_KEY > SD_ID128_MAKE(d3,1e,48,fa,90,fe,4b,4c,9d,af,d5,d7,a1,b1,2e,8a) > + > void siphash24(uint8_t out[8], const void *in, size_t inlen, const uint8_t > k[16]); > diff --git a/src/systemd/sd-ipv4ll.h b/src/systemd/sd-ipv4ll.h > index 0207006..2397d43 100644 > --- a/src/systemd/sd-ipv4ll.h > +++ b/src/systemd/sd-ipv4ll.h > @@ -42,6 +42,7 @@ int sd_ipv4ll_get_address(sd_ipv4ll *ll, struct in_addr > *address); > int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_cb_t cb, void *userdata); > int sd_ipv4ll_set_mac(sd_ipv4ll *ll, const struct ether_addr *addr); > int sd_ipv4ll_set_index(sd_ipv4ll *ll, int interface_index); > +int sd_ipv4ll_set_address_seed (sd_ipv4ll *ll, uint64_t entropy); > int sd_ipv4ll_start (sd_ipv4ll *ll); > int sd_ipv4ll_stop (sd_ipv4ll *ll); > void sd_ipv4ll_free (sd_ipv4ll *ll); > diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c > index 62439c0..41384b8 100644 > --- a/src/udev/net/link-config.c > +++ b/src/udev/net/link-config.c > @@ -302,36 +302,11 @@ static int get_mac(struct udev_device *device, bool > want_random, struct ether_ad > if (want_random) > random_bytes(mac->ether_addr_octet, ETH_ALEN); > else { > - const char *name; > uint8_t result[8]; > - size_t l, sz; > - uint8_t *v; > - > - /* fetch some persistent data unique (on this machine) to > this device */ > - name = udev_device_get_property_value(device, > "ID_NET_NAME_ONBOARD"); > - if (!name) { > - name = udev_device_get_property_value(device, > "ID_NET_NAME_SLOT"); > - if (!name) { > - name = > udev_device_get_property_value(device, "ID_NET_NAME_PATH"); > - if (!name) > - return -ENOENT; > - } > - } > > - l = strlen(name); > - sz = sizeof(sd_id128_t) + l; > - v = alloca(sz); > - > - /* fetch some persistent data unique to this machine */ > - r = sd_id128_get_machine((sd_id128_t*) v); > + r = net_get_unique_predictable_data(device, > (uint64_t*)result); > if (r < 0) > return r; > - memcpy(v + sizeof(sd_id128_t), name, l); > - > - /* Let's hash the machine ID plus the device name. We > - * use a fixed, but originally randomly created hash > - * key here. */ > - siphash24(result, v, sz, HASH_KEY.bytes); > > assert_cc(ETH_ALEN <= sizeof(result)); > memcpy(mac->ether_addr_octet, result, ETH_ALEN); > --
Applied with some minor changes, please check that it is still ok :) Thanks for your work on this! Cheers, Tom _______________________________________________ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel