[systemd-commits] 71 commits - configure.ac DISTRO_PORTING Makefile.am man/custom-html.xsl man/sd_bus_default.xml man/sd_bus_new.xml man/systemd.netdev.xml README src/basic src/boot src/core src/libsystemd src/libsystemd-network src/login src/network src/resolve src/resolve-host src/shared src/systemd src/test TODO units/emergency.service.in

David Herrmann dvdhrm at kemper.freedesktop.org
Wed Jul 15 13:05:34 PDT 2015


 DISTRO_PORTING                               |   19 
 Makefile.am                                  |    5 
 README                                       |   18 
 TODO                                         |    4 
 configure.ac                                 |    3 
 man/custom-html.xsl                          |  180 +++++---
 man/sd_bus_default.xml                       |   66 ++-
 man/sd_bus_new.xml                           |   16 
 man/systemd.netdev.xml                       |   10 
 src/basic/path-util.c                        |    6 
 src/basic/util.c                             |  199 +++++++++
 src/basic/util.h                             |    7 
 src/boot/bootctl.c                           |    2 
 src/boot/efi/boot.c                          |   21 
 src/core/main.c                              |   42 +
 src/core/path.c                              |    2 
 src/libsystemd-network/dhcp-lease-internal.h |    2 
 src/libsystemd-network/dhcp-protocol.h       |    1 
 src/libsystemd-network/sd-dhcp-lease.c       |   68 ++-
 src/libsystemd/sd-bus/bus-objects.c          |    6 
 src/libsystemd/sd-bus/bus-slot.c             |    2 
 src/libsystemd/sd-bus/bus-socket.c           |   20 
 src/libsystemd/sd-bus/test-bus-objects.c     |    3 
 src/libsystemd/sd-device/sd-device.c         |    8 
 src/libsystemd/sd-netlink/netlink-internal.h |    2 
 src/libsystemd/sd-netlink/netlink-message.c  |   48 +-
 src/login/logind-dbus.c                      |   11 
 src/login/logind-seat.c                      |   18 
 src/login/logind-session.c                   |   10 
 src/login/logind-session.h                   |    2 
 src/login/org.freedesktop.login1.conf        |   72 +++
 src/network/networkd-netdev-gperf.gperf      |    1 
 src/network/networkd-netdev-tuntap.c         |    3 
 src/network/networkd-netdev-tuntap.h         |    1 
 src/resolve-host/resolve-host.c              |    4 
 src/resolve/resolved-dns-packet.c            |   82 +++
 src/resolve/resolved-dns-packet.h            |   17 
 src/resolve/resolved-dns-rr.c                |   70 ++-
 src/resolve/resolved-dns-rr.h                |    8 
 src/resolve/resolved-dns-scope.c             |   33 -
 src/resolve/resolved-dns-scope.h             |    4 
 src/resolve/resolved-dns-server.c            |   44 +-
 src/resolve/resolved-dns-server.h            |    7 
 src/resolve/resolved-dns-transaction.c       |  134 +++++-
 src/resolve/resolved-dns-transaction.h       |   12 
 src/resolve/resolved-link.c                  |   23 -
 src/resolve/resolved-llmnr.c                 |  473 ++++++++++++++++++++++
 src/resolve/resolved-llmnr.h                 |   34 +
 src/resolve/resolved-manager.c               |  569 +--------------------------
 src/resolve/resolved-manager.h               |   13 
 src/shared/efivars.c                         |   14 
 src/systemd/sd-bus.h                         |    2 
 src/systemd/sd-dhcp-lease.h                  |    2 
 src/test/test-util.c                         |  125 +++++
 units/emergency.service.in                   |    2 
 55 files changed, 1724 insertions(+), 826 deletions(-)

New commits:
commit 7ee7b225bd2fc3e7a3980f5fb7b10dfc6e205578
Author: David Herrmann <dh.herrmann at gmail.com>
Date:   Wed Jul 15 15:36:54 2015 +0200

    build: add convenience target 'build-sources'
    
    This target allows to trigger a build of $(BUILT_SOURCES) manually. This
    is handy if you tend to use 'make systemd-foobar' to directly build a
    single binary. Those do not pull in $(BUILT_SOURCES), unfortunately. See
    automake docs for that.

diff --git a/Makefile.am b/Makefile.am
index c038fed..3c0ce32 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -6139,6 +6139,9 @@ hwdb-update:
 		http://standards.ieee.org/develop/regauth/iab/iab.txt && \
 	./ids-update.pl )
 
+.PHONY: built-sources
+built-sources: $(BUILT_SOURCES)
+
 .PHONY: git-tag
 git-tag:
 	git tag -s "v$(VERSION)" -m "systemd $(VERSION)"

commit 7d67077f78d4a43f214c240359ad5f7284d086fa
Author: David Herrmann <dh.herrmann at gmail.com>
Date:   Wed Jul 15 14:35:15 2015 +0200

    sd-bus: fix object tree to be deeper than 2 levels
    
    So right now our object-tree is limited to 2 levels at most
    ('/' and '/foo/...../bar'). We never link any intermediate levels, even
    though that was clearly the plan. Fix the bus_node_allocate() helper to
    actually link all intermediate nodes, too, not just the root node.
    
    This fixes a simple inverse ptr-diff bug.
    
    The downside of this fix is that we clearly never tested (nor used) the
    object tree in any way. The only reason that the introspection works is
    that our enumerators shortcut the object tree.
    
    Lets see whether that code actually works..
    
    Thanks to: Nathaniel McCallum <nathaniel at themccallums.org>
    ..for reporting this. See #524 for an actual example code.

diff --git a/src/libsystemd/sd-bus/bus-objects.c b/src/libsystemd/sd-bus/bus-objects.c
index b3cc28e..cbdf655 100644
--- a/src/libsystemd/sd-bus/bus-objects.c
+++ b/src/libsystemd/sd-bus/bus-objects.c
@@ -1416,7 +1416,7 @@ static struct node *bus_node_allocate(sd_bus *bus, const char *path) {
                 e = strrchr(path, '/');
                 assert(e);
 
-                p = strndupa(path, MAX(1, path - e));
+                p = strndupa(path, MAX(1, e - path));
 
                 parent = bus_node_allocate(bus, p);
                 if (!parent)

commit bf4c113e179650c07a8f95a14d71f365dbfe66e4
Author: David Herrmann <dh.herrmann at gmail.com>
Date:   Wed Jul 15 12:30:08 2015 +0200

    sd-device: never return NULL+0
    
    It is highly confusing if a getter function returns 0, but the value is
    set to NULL. This, right now, triggers assertions as code relies on the
    returned values to be non-NULL.
    
    Like with sd-bus-creds and friends, return 0 only if a value is actually
    available.
    
    Discussed with Tom, and actually fixes real bugs as in #512.

diff --git a/src/libsystemd/sd-device/sd-device.c b/src/libsystemd/sd-device/sd-device.c
index b274f71..7cea5a0 100644
--- a/src/libsystemd/sd-device/sd-device.c
+++ b/src/libsystemd/sd-device/sd-device.c
@@ -791,6 +791,9 @@ _public_ int sd_device_get_subsystem(sd_device *device, const char **ret) {
                 device->subsystem_set = true;
         }
 
+        if (!device->subsystem)
+                return -ENOENT;
+
         *ret = device->subsystem;
 
         return 0;
@@ -908,6 +911,9 @@ _public_ int sd_device_get_driver(sd_device *device, const char **ret) {
                         return log_debug_errno(r, "sd-device: could not set driver for %s: %m", device->devpath);
         }
 
+        if (!device->driver)
+                return -ENOENT;
+
         *ret = device->driver;
 
         return 0;
@@ -1002,6 +1008,8 @@ _public_ int sd_device_get_sysname(sd_device *device, const char **ret) {
                         return r;
         }
 
+        assert_return(device->sysname, -ENOENT);
+
         *ret = device->sysname;
 
         return 0;

commit ab822b624bc48410c8d7bd3be1c88c399a44adae
Author: David Herrmann <dh.herrmann at gmail.com>
Date:   Wed Jul 15 11:58:03 2015 +0200

    sd-boot: ignore missing /etc/machine-id
    
    If /etc/machine-id is missing (eg., gold images), we should not fail
    installing sd-boot. This is a perfectly fine use-case and we should simply
    skip installing the default loader config in that case.

diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c
index ed69fb0..faab82d 100644
--- a/src/boot/bootctl.c
+++ b/src/boot/bootctl.c
@@ -888,7 +888,7 @@ static int install_loader_config(const char *esp_path) {
 
         f = fopen("/etc/machine-id", "re");
         if (!f)
-                return -errno;
+                return errno == ENOENT ? 0 : -errno;
 
         if (fgets(line, sizeof(line), f) != NULL) {
                 char *s;

commit 8a2abb30b8a4ef97eb69ecdabd31da996abc3df0
Merge: dad8f7f 2a2953b
Author: Daniel Mack <github at zonque.org>
Date:   Tue Jul 14 16:10:11 2015 -0400

    Merge pull request #587 from teg/unbase64mem-memleak
    
    basic: util - fix memleak on error in unbase64mem()


commit 2a2953b35505fb7f603b490c72edd76bd6469540
Author: Tom Gundersen <teg at jklm.no>
Date:   Tue Jul 14 21:14:45 2015 +0200

    basic: util - fix memleak on error in unbase64mem()

diff --git a/src/basic/util.c b/src/basic/util.c
index bc917ae..a45f5f8 100644
--- a/src/basic/util.c
+++ b/src/basic/util.c
@@ -1030,9 +1030,9 @@ char *base64mem(const void *p, size_t l) {
 }
 
 int unbase64mem(const char *p, size_t l, void **mem, size_t *_len) {
-        _cleanup_free_ uint8_t *t = NULL;
+        _cleanup_free_ uint8_t *r = NULL;
         int a, b, c, d;
-        uint8_t *r, *z;
+        uint8_t *z;
         const char *x;
         size_t len;
 

commit dad8f7f2b6eb34bead17df9b3966da9c4b4d79db
Merge: 9ecec7d a051852
Author: Tom Gundersen <teg at jklm.no>
Date:   Tue Jul 14 20:17:11 2015 +0200

    Merge pull request #538 from mischief/multiple-routers
    
    sd-dhcp-lease: fix handling of multiple routers
    
    We only support one router, but in case more than one is given, we now ignore subsequent ones, rather than fall over.


commit 9ecec7d7668b54fa87a0a5a637ec8f0ef911766b
Merge: c0d645b d23a27a
Author: Daniel Mack <github at zonque.org>
Date:   Tue Jul 14 13:43:18 2015 -0400

    Merge pull request #586 from teg/resolved-rrs-3
    
    resolved: minor improvements to RR handling


commit d23a27a964748967e1ad20e86de869a753af555b
Author: Tom Gundersen <teg at jklm.no>
Date:   Tue Jul 14 04:32:29 2015 +0200

    resolved: improve printing of unknown RRs
    
    This implements the recommendations from RFC3597.

diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c
index dd3e44f..676b777 100644
--- a/src/resolve/resolved-dns-rr.c
+++ b/src/resolve/resolved-dns-rr.c
@@ -171,19 +171,19 @@ const struct hash_ops dns_resource_key_hash_ops = {
 };
 
 int dns_resource_key_to_string(const DnsResourceKey *key, char **ret) {
-        char cbuf[DECIMAL_STR_MAX(uint16_t)], tbuf[DECIMAL_STR_MAX(uint16_t)];
+        char cbuf[strlen("CLASS") + DECIMAL_STR_MAX(uint16_t)], tbuf[strlen("TYPE") + DECIMAL_STR_MAX(uint16_t)];
         const char *c, *t;
         char *s;
 
         c = dns_class_to_string(key->class);
         if (!c) {
-                sprintf(cbuf, "%i", key->class);
+                sprintf(cbuf, "CLASS%u", key->class);
                 c = cbuf;
         }
 
         t = dns_type_to_string(key->type);
         if (!t){
-                sprintf(tbuf, "%i", key->type);
+                sprintf(tbuf, "TYPE%u", key->type);
                 t = tbuf;
         }
 
@@ -709,8 +709,8 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
                 if (!t)
                         return -ENOMEM;
 
-                s = strjoin(k, " ", t, NULL);
-                if (!s)
+                r = asprintf(&s, "%s \\# %"PRIu8" %s", k, rr->generic.size, t);
+                if (r < 0)
                         return -ENOMEM;
                 break;
         }

commit c0d645b51f6a65a03cce4e29ed276ccdcb5b6ab0
Merge: ca97001 d20b166
Author: Daniel Mack <github at zonque.org>
Date:   Tue Jul 14 13:26:16 2015 -0400

    Merge pull request #585 from teg/resolved-harden-2
    
    resolved: harden


commit ca970016b7e5176e94eee3af24a70d5b3355018f
Merge: 73b836e 4c641e9
Author: David Herrmann <dh.herrmann at gmail.com>
Date:   Tue Jul 14 19:19:39 2015 +0200

    Merge commit 'refs/pull/436/head' of https://github.com/systemd/systemd
    
    This merges:
      sd-netlink: respect attribute type flags
    
    ..fixing a conflict due to a typo fix.

diff --cc src/libsystemd/sd-netlink/netlink-internal.h
index 6f51ebe,4aa7583..4026e2c
--- a/src/libsystemd/sd-netlink/netlink-internal.h
+++ b/src/libsystemd/sd-netlink/netlink-internal.h
@@@ -93,7 -93,9 +93,9 @@@ struct sd_netlink 
  };
  
  struct netlink_attribute {
 -        size_t offset; /* offset from hdr to attirubte */
 +        size_t offset; /* offset from hdr to attribute */
+         bool nested:1;
+         bool net_byteorder:1;
  };
  
  struct netlink_container {

commit abf126a355e2f2b62b6c51ab3bb37895d1e3eee7
Author: Tom Gundersen <teg at jklm.no>
Date:   Mon Jul 13 01:51:03 2015 +0200

    resolved: rr - add DS support
    
    Needed for DNSSEC.

diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c
index fa0516f..ea7975a 100644
--- a/src/resolve/resolved-dns-packet.c
+++ b/src/resolve/resolved-dns-packet.c
@@ -652,6 +652,22 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star
                 r = dns_packet_append_uint32(p, rr->loc.altitude, NULL);
                 break;
 
+        case DNS_TYPE_DS:
+                r = dns_packet_append_uint16(p, rr->ds.key_tag, NULL);
+                if (r < 0)
+                        goto fail;
+
+                r = dns_packet_append_uint8(p, rr->ds.algorithm, NULL);
+                if (r < 0)
+                        goto fail;
+
+                r = dns_packet_append_uint8(p, rr->ds.digest_type, NULL);
+                if (r < 0)
+                        goto fail;
+
+                r = dns_packet_append_blob(p, rr->ds.digest, rr->ds.digest_size, NULL);
+                break;
+
         case DNS_TYPE_SSHFP:
                 r = dns_packet_append_uint8(p, rr->sshfp.algorithm, NULL);
                 if (r < 0)
@@ -1262,6 +1278,26 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
                 }
         }
 
+        case DNS_TYPE_DS:
+                r = dns_packet_read_uint16(p, &rr->ds.key_tag, NULL);
+                if (r < 0)
+                        goto fail;
+
+                r = dns_packet_read_uint8(p, &rr->ds.algorithm, NULL);
+                if (r < 0)
+                        goto fail;
+
+                r = dns_packet_read_uint8(p, &rr->ds.digest_type, NULL);
+                if (r < 0)
+                        goto fail;
+
+                r = dns_packet_read_public_key(p, rdlength - 4,
+                                               &rr->ds.digest, &rr->ds.digest_size,
+                                               NULL);
+                if (r < 0)
+                        goto fail;
+
+                break;
         case DNS_TYPE_SSHFP:
                 r = dns_packet_read_uint8(p, &rr->sshfp.algorithm, NULL);
                 if (r < 0)
diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c
index 4471644..dd3e44f 100644
--- a/src/resolve/resolved-dns-rr.c
+++ b/src/resolve/resolved-dns-rr.c
@@ -271,6 +271,10 @@ DnsResourceRecord* dns_resource_record_unref(DnsResourceRecord *rr) {
                         free(rr->mx.exchange);
                         break;
 
+                case DNS_TYPE_DS:
+                        free(rr->ds.digest);
+                        break;
+
                 case DNS_TYPE_SSHFP:
                         free(rr->sshfp.key);
                         break;
@@ -409,6 +413,13 @@ int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecor
                        a->loc.longitude == b->loc.longitude &&
                        a->loc.altitude == b->loc.altitude;
 
+        case DNS_TYPE_DS:
+                return a->ds.key_tag == b->ds.key_tag &&
+                       a->ds.algorithm == b->ds.algorithm &&
+                       a->ds.digest_type == b->ds.digest_type &&
+                       a->ds.digest_size == b->ds.digest_size &&
+                       memcmp(a->ds.digest, b->ds.digest, a->ds.digest_size) == 0;
+
         case DNS_TYPE_SSHFP:
                 return a->sshfp.algorithm == b->sshfp.algorithm &&
                        a->sshfp.fptype == b->sshfp.fptype &&
@@ -604,6 +615,21 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
                         return -ENOMEM;
                 break;
 
+        case DNS_TYPE_DS:
+                t = hexmem(rr->ds.digest, rr->ds.digest_size);
+                if (!t)
+                        return -ENOMEM;
+
+                r = asprintf(&s, "%s %u %u %u %s",
+                             k,
+                             rr->ds.key_tag,
+                             rr->ds.algorithm,
+                             rr->ds.digest_type,
+                             t);
+                if (r < 0)
+                        return -ENOMEM;
+                break;
+
         case DNS_TYPE_SSHFP:
                 t = hexmem(rr->sshfp.key, rr->sshfp.key_size);
                 if (!t)
diff --git a/src/resolve/resolved-dns-rr.h b/src/resolve/resolved-dns-rr.h
index 26796c8..b375d6b 100644
--- a/src/resolve/resolved-dns-rr.h
+++ b/src/resolve/resolved-dns-rr.h
@@ -109,6 +109,14 @@ struct DnsResourceRecord {
                 } loc;
 
                 struct {
+                        uint16_t key_tag;
+                        uint8_t algorithm;
+                        uint8_t digest_type;
+                        void *digest;
+                        size_t digest_size;
+                } ds;
+
+                struct {
                         uint8_t algorithm;
                         uint8_t fptype;
                         void *key;

commit 7c6423e19136a7b7b6ef3fe06b94822e582dda27
Author: Tom Gundersen <teg at jklm.no>
Date:   Mon Jul 13 00:58:00 2015 +0200

    resolved: rr - print formated timestamps in RRSIG

diff --git a/TODO b/TODO
index 17295fe..b3406dd 100644
--- a/TODO
+++ b/TODO
@@ -343,7 +343,6 @@ Features:
     we always process them before we process client requests
   - DNSSEC
         - add display of private key types (http://tools.ietf.org/html/rfc4034#appendix-A.1.1)?
-        - add nice formatting of DNS timestamps
   - DNS
         - search paths
   - mDNS/DNS-SD
diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c
index f46f868..4471644 100644
--- a/src/resolve/resolved-dns-rr.c
+++ b/src/resolve/resolved-dns-rr.c
@@ -474,6 +474,21 @@ static char* format_location(uint32_t latitude, uint32_t longitude, uint32_t alt
         return s;
 }
 
+static int format_timestamp_dns(char *buf, size_t l, time_t sec) {
+        struct tm tm;
+
+        assert(buf);
+        assert(l > strlen("YYYYMMDDHHmmSS"));
+
+        if (!gmtime_r(&sec, &tm))
+                return -EINVAL;
+
+        if (strftime(buf, l, "%Y%m%d%H%M%S", &tm) <= 0)
+                return -EINVAL;
+
+        return 0;
+}
+
 int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
         _cleanup_free_ char *k = NULL, *t = NULL;
         char *s;
@@ -625,6 +640,7 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
 
         case DNS_TYPE_RRSIG: {
                 const char *type, *alg;
+                char expiration[strlen("YYYYMMDDHHmmSS") + 1], inception[strlen("YYYYMMDDHHmmSS") + 1];
 
                 type = dns_type_to_string(rr->rrsig.type_covered);
                 alg = dnssec_algorithm_to_string(rr->rrsig.algorithm);
@@ -633,10 +649,18 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
                 if (!t)
                         return -ENOMEM;
 
+                r = format_timestamp_dns(expiration, sizeof(expiration), rr->rrsig.expiration);
+                if (r < 0)
+                        return r;
+
+                r = format_timestamp_dns(inception, sizeof(inception), rr->rrsig.inception);
+                if (r < 0)
+                        return r;
+
                 /* TYPE?? follows
                  * http://tools.ietf.org/html/rfc3597#section-5 */
 
-                r = asprintf(&s, "%s %s%.*u %.*s%.*u %u %u %u %u %u %s %s",
+                r = asprintf(&s, "%s %s%.*u %.*s%.*u %u %u %s %s %u %s %s",
                              k,
                              type ?: "TYPE",
                              type ? 0 : 1, type ? 0u : (unsigned) rr->rrsig.type_covered,
@@ -644,8 +668,8 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
                              alg ? 0 : 1, alg ? 0u : (unsigned) rr->rrsig.algorithm,
                              rr->rrsig.labels,
                              rr->rrsig.original_ttl,
-                             rr->rrsig.expiration,
-                             rr->rrsig.inception,
+                             expiration,
+                             inception,
                              rr->rrsig.key_tag,
                              rr->rrsig.signer,
                              t);

commit d20b1667dbab8bccf69735523a0d5fc645e81b80
Author: Tom Gundersen <teg at jklm.no>
Date:   Thu Jul 9 14:19:55 2015 +0200

    resolved: use one UDP socket per transaction
    
    We used to have one global socket, use one per transaction instead. This
    has the side-effect of giving us a random UDP port per transaction, and
    hence increasing the entropy and making cache poisoining significantly
    harder to achieve.
    
    We still reuse the same port number for packets belonging to the same
    transaction (resent packets).

diff --git a/TODO b/TODO
index c1b57be..1f5023c 100644
--- a/TODO
+++ b/TODO
@@ -353,7 +353,6 @@ Features:
   - edns0
   - dname
   - cname on PTR (?)
-  - maybe randomize DNS UDP source ports
 
 * Allow multiple ExecStart= for all Type= settings, so that we can cover rescue.service nicely
 
diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c
index 34d4a98..7b72c09 100644
--- a/src/resolve/resolved-dns-scope.c
+++ b/src/resolve/resolved-dns-scope.c
@@ -125,7 +125,7 @@ void dns_scope_next_dns_server(DnsScope *s) {
                 manager_next_dns_server(s->manager);
 }
 
-int dns_scope_emit(DnsScope *s, DnsPacket *p, DnsServer **server) {
+int dns_scope_emit(DnsScope *s, DnsTransaction *t, DnsPacket *p, DnsServer **server) {
         DnsServer *srv = NULL;
         union in_addr_union addr;
         int ifindex = 0, r;
@@ -163,9 +163,9 @@ int dns_scope_emit(DnsScope *s, DnsPacket *p, DnsServer **server) {
                         return -EMSGSIZE;
 
                 if (family == AF_INET)
-                        fd = manager_dns_ipv4_fd(s->manager);
+                        fd = transaction_dns_ipv4_fd(t);
                 else if (family == AF_INET6)
-                        fd = manager_dns_ipv6_fd(s->manager);
+                        fd = transaction_dns_ipv6_fd(t);
                 else
                         return -EAFNOSUPPORT;
                 if (fd < 0)
@@ -700,7 +700,7 @@ static int on_conflict_dispatch(sd_event_source *es, usec_t usec, void *userdata
                         return 0;
                 }
 
-                r = dns_scope_emit(scope, p, NULL);
+                r = dns_scope_emit(scope, NULL, p, NULL);
                 if (r < 0)
                         log_debug_errno(r, "Failed to send conflict packet: %m");
         }
diff --git a/src/resolve/resolved-dns-scope.h b/src/resolve/resolved-dns-scope.h
index f836407..5c5ccc7 100644
--- a/src/resolve/resolved-dns-scope.h
+++ b/src/resolve/resolved-dns-scope.h
@@ -65,7 +65,7 @@ struct DnsScope {
 int dns_scope_new(Manager *m, DnsScope **ret, Link *l, DnsProtocol p, int family);
 DnsScope* dns_scope_free(DnsScope *s);
 
-int dns_scope_emit(DnsScope *s, DnsPacket *p, DnsServer **server);
+int dns_scope_emit(DnsScope *s, DnsTransaction *t, DnsPacket *p, DnsServer **server);
 int dns_scope_tcp_socket(DnsScope *s, int family, const union in_addr_union *address, uint16_t port, DnsServer **server);
 
 DnsScopeMatch dns_scope_good_domain(DnsScope *s, int ifindex, uint64_t flags, const char *domain);
diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c
index 3260ded..e468f24 100644
--- a/src/resolve/resolved-dns-transaction.c
+++ b/src/resolve/resolved-dns-transaction.c
@@ -39,6 +39,11 @@ DnsTransaction* dns_transaction_free(DnsTransaction *t) {
         dns_packet_unref(t->received);
         dns_answer_unref(t->cached);
 
+        sd_event_source_unref(t->dns_ipv4_event_source);
+        sd_event_source_unref(t->dns_ipv6_event_source);
+        safe_close(t->dns_ipv4_fd);
+        safe_close(t->dns_ipv6_fd);
+
         dns_server_unref(t->server);
         dns_stream_free(t->stream);
 
@@ -89,6 +94,8 @@ int dns_transaction_new(DnsTransaction **ret, DnsScope *s, DnsQuestion *q) {
         if (!t)
                 return -ENOMEM;
 
+        t->dns_ipv4_fd = t->dns_ipv6_fd = -1;
+
         t->question = dns_question_ref(q);
 
         do
@@ -590,7 +597,7 @@ int dns_transaction_go(DnsTransaction *t) {
                 DnsServer *server;
 
                 /* Try via UDP, and if that fails due to large size try via TCP */
-                r = dns_scope_emit(t->scope, t->sent, &server);
+                r = dns_scope_emit(t->scope, t, t->sent, &server);
                 if (r >= 0)
                         t->server = dns_server_ref(server);
                 else if (r == -EMSGSIZE)
@@ -625,6 +632,91 @@ int dns_transaction_go(DnsTransaction *t) {
         return 1;
 }
 
+static int on_dns_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
+        _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
+        DnsTransaction *t = userdata;
+        int r;
+
+        assert(t);
+        assert(t->scope);
+
+        r = manager_recv(t->scope->manager, fd, DNS_PROTOCOL_DNS, &p);
+        if (r <= 0)
+                return r;
+
+        if (dns_packet_validate_reply(p) > 0 &&
+            DNS_PACKET_ID(p) == t->id) {
+                dns_transaction_process_reply(t, p);
+        } else
+                log_debug("Invalid DNS packet.");
+
+        return 0;
+}
+
+int transaction_dns_ipv4_fd(DnsTransaction *t) {
+        const int one = 1;
+        int r;
+
+        assert(t);
+        assert(t->scope);
+        assert(t->scope->manager);
+
+        if (t->dns_ipv4_fd >= 0)
+                return t->dns_ipv4_fd;
+
+        t->dns_ipv4_fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
+        if (t->dns_ipv4_fd < 0)
+                return -errno;
+
+        r = setsockopt(t->dns_ipv4_fd, IPPROTO_IP, IP_PKTINFO, &one, sizeof(one));
+        if (r < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        r = sd_event_add_io(t->scope->manager->event, &t->dns_ipv4_event_source, t->dns_ipv4_fd, EPOLLIN, on_dns_packet, t);
+        if (r < 0)
+                goto fail;
+
+        return t->dns_ipv4_fd;
+
+fail:
+        t->dns_ipv4_fd = safe_close(t->dns_ipv4_fd);
+        return r;
+}
+
+int transaction_dns_ipv6_fd(DnsTransaction *t) {
+        const int one = 1;
+        int r;
+
+        assert(t);
+        assert(t->scope);
+        assert(t->scope->manager);
+
+        if (t->dns_ipv6_fd >= 0)
+                return t->dns_ipv6_fd;
+
+        t->dns_ipv6_fd = socket(AF_INET6, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
+        if (t->dns_ipv6_fd < 0)
+                return -errno;
+
+        r = setsockopt(t->dns_ipv6_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one));
+        if (r < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        r = sd_event_add_io(t->scope->manager->event, &t->dns_ipv6_event_source, t->dns_ipv6_fd, EPOLLIN, on_dns_packet, t);
+        if (r < 0)
+                goto fail;
+
+        return t->dns_ipv6_fd;
+
+fail:
+        t->dns_ipv6_fd = safe_close(t->dns_ipv6_fd);
+        return r;
+}
+
 static const char* const dns_transaction_state_table[_DNS_TRANSACTION_STATE_MAX] = {
         [DNS_TRANSACTION_NULL] = "null",
         [DNS_TRANSACTION_PENDING] = "pending",
diff --git a/src/resolve/resolved-dns-transaction.h b/src/resolve/resolved-dns-transaction.h
index 42f846e..87f342c 100644
--- a/src/resolve/resolved-dns-transaction.h
+++ b/src/resolve/resolved-dns-transaction.h
@@ -61,6 +61,12 @@ struct DnsTransaction {
         sd_event_source *timeout_event_source;
         unsigned n_attempts;
 
+        int dns_ipv4_fd;
+        int dns_ipv6_fd;
+
+        sd_event_source *dns_ipv4_event_source;
+        sd_event_source *dns_ipv6_event_source;
+
         /* the active server */
         DnsServer *server;
 
@@ -89,6 +95,9 @@ int dns_transaction_go(DnsTransaction *t);
 void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p);
 void dns_transaction_complete(DnsTransaction *t, DnsTransactionState state);
 
+int transaction_dns_ipv4_fd(DnsTransaction *t);
+int transaction_dns_ipv6_fd(DnsTransaction *t);
+
 const char* dns_transaction_state_to_string(DnsTransactionState p) _const_;
 DnsTransactionState dns_transaction_state_from_string(const char *s) _pure_;
 
diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c
index e050092..17de14b 100644
--- a/src/resolve/resolved-manager.c
+++ b/src/resolve/resolved-manager.c
@@ -404,7 +404,6 @@ int manager_new(Manager **ret) {
         if (!m)
                 return -ENOMEM;
 
-        m->dns_ipv4_fd = m->dns_ipv6_fd = -1;
         m->llmnr_ipv4_udp_fd = m->llmnr_ipv6_udp_fd = -1;
         m->llmnr_ipv4_tcp_fd = m->llmnr_ipv6_tcp_fd = -1;
         m->hostname_fd = -1;
@@ -486,11 +485,6 @@ Manager *manager_free(Manager *m) {
         sd_event_source_unref(m->network_event_source);
         sd_network_monitor_unref(m->network_monitor);
 
-        sd_event_source_unref(m->dns_ipv4_event_source);
-        sd_event_source_unref(m->dns_ipv6_event_source);
-        safe_close(m->dns_ipv4_fd);
-        safe_close(m->dns_ipv6_fd);
-
         manager_llmnr_stop(m);
 
         sd_bus_slot_unref(m->prepare_for_sleep_slot);
@@ -929,89 +923,6 @@ int manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret) {
         return 1;
 }
 
-static int on_dns_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
-        _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
-        DnsTransaction *t = NULL;
-        Manager *m = userdata;
-        int r;
-
-        r = manager_recv(m, fd, DNS_PROTOCOL_DNS, &p);
-        if (r <= 0)
-                return r;
-
-        if (dns_packet_validate_reply(p) > 0) {
-                t = hashmap_get(m->dns_transactions, UINT_TO_PTR(DNS_PACKET_ID(p)));
-                if (!t)
-                        return 0;
-
-                dns_transaction_process_reply(t, p);
-
-        } else
-                log_debug("Invalid DNS packet.");
-
-        return 0;
-}
-
-int manager_dns_ipv4_fd(Manager *m) {
-        const int one = 1;
-        int r;
-
-        assert(m);
-
-        if (m->dns_ipv4_fd >= 0)
-                return m->dns_ipv4_fd;
-
-        m->dns_ipv4_fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
-        if (m->dns_ipv4_fd < 0)
-                return -errno;
-
-        r = setsockopt(m->dns_ipv4_fd, IPPROTO_IP, IP_PKTINFO, &one, sizeof(one));
-        if (r < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        r = sd_event_add_io(m->event, &m->dns_ipv4_event_source, m->dns_ipv4_fd, EPOLLIN, on_dns_packet, m);
-        if (r < 0)
-                goto fail;
-
-        return m->dns_ipv4_fd;
-
-fail:
-        m->dns_ipv4_fd = safe_close(m->dns_ipv4_fd);
-        return r;
-}
-
-int manager_dns_ipv6_fd(Manager *m) {
-        const int one = 1;
-        int r;
-
-        assert(m);
-
-        if (m->dns_ipv6_fd >= 0)
-                return m->dns_ipv6_fd;
-
-        m->dns_ipv6_fd = socket(AF_INET6, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
-        if (m->dns_ipv6_fd < 0)
-                return -errno;
-
-        r = setsockopt(m->dns_ipv6_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one));
-        if (r < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        r = sd_event_add_io(m->event, &m->dns_ipv6_event_source, m->dns_ipv6_fd, EPOLLIN, on_dns_packet, m);
-        if (r < 0)
-                goto fail;
-
-        return m->dns_ipv6_fd;
-
-fail:
-        m->dns_ipv6_fd = safe_close(m->dns_ipv6_fd);
-        return r;
-}
-
 static int sendmsg_loop(int fd, struct msghdr *mh, int flags) {
         int r;
 
diff --git a/src/resolve/resolved-manager.h b/src/resolve/resolved-manager.h
index 4e70a5b..005f844 100644
--- a/src/resolve/resolved-manager.h
+++ b/src/resolve/resolved-manager.h
@@ -65,12 +65,6 @@ struct Manager {
         unsigned n_dns_streams;
 
         /* Unicast dns */
-        int dns_ipv4_fd;
-        int dns_ipv6_fd;
-
-        sd_event_source *dns_ipv4_event_source;
-        sd_event_source *dns_ipv6_event_source;
-
         LIST_HEAD(DnsServer, dns_servers);
         LIST_HEAD(DnsServer, fallback_dns_servers);
         DnsServer *current_dns_server;
@@ -128,9 +122,6 @@ uint32_t manager_find_mtu(Manager *m);
 int manager_send(Manager *m, int fd, int ifindex, int family, const union in_addr_union *addr, uint16_t port, DnsPacket *p);
 int manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret);
 
-int manager_dns_ipv4_fd(Manager *m);
-int manager_dns_ipv6_fd(Manager *m);
-
 int manager_find_ifindex(Manager *m, int family, const union in_addr_union *in_addr);
 LinkAddress* manager_find_link_address(Manager *m, int family, const union in_addr_union *in_addr);
 

commit 29815b6c608b836cada5e349d06a96b63eaa65f3
Author: Tom Gundersen <teg at jklm.no>
Date:   Thu Jul 9 02:58:15 2015 +0200

    resolved: implement RFC5452
    
    This improves the resilience against cache poisoning by being stricter
    about only accepting responses that match precisely the requst they
    are in reply to.
    
    It should be noted that we still only use one port (which is picked
    at random), rather than one port for each transaction. Port
    randomization would improve things further, but is not required by
    the RFC.

diff --git a/TODO b/TODO
index 2904e2b..c1b57be 100644
--- a/TODO
+++ b/TODO
@@ -354,7 +354,6 @@ Features:
   - dname
   - cname on PTR (?)
   - maybe randomize DNS UDP source ports
-  - maybe compare query section of DNS replies
 
 * Allow multiple ExecStart= for all Type= settings, so that we can cover rescue.service nicely
 
diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c
index 7fa73cd..3260ded 100644
--- a/src/resolve/resolved-dns-transaction.c
+++ b/src/resolve/resolved-dns-transaction.c
@@ -338,10 +338,15 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) {
         if (t->scope->protocol == DNS_PROTOCOL_DNS) {
 
                 /* For DNS we are fine with accepting packets on any
-                 * interface, but the source IP address must be one of
-                 * a valid DNS server */
+                 * interface, but the source IP address must be the
+                 * one of the DNS server we queried */
 
-                if (!dns_scope_good_dns_server(t->scope, p->family, &p->sender))
+                assert(t->server);
+
+                if (t->server->family != p->family)
+                        return;
+
+                if (!in_addr_equal(p->family, &p->sender, &t->server->address))
                         return;
 
                 if (p->sender_port != 53)
@@ -403,6 +408,11 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) {
                 return;
         }
 
+        /* Only consider responses with equivalent query section to the request */
+        if (!dns_question_is_superset(p->question, t->question) ||
+            !dns_question_is_superset(t->question, p->question))
+                dns_transaction_complete(t, DNS_TRANSACTION_INVALID_REPLY);
+
         /* According to RFC 4795, section 2.9. only the RRs from the answer section shall be cached */
         dns_cache_put(&t->scope->cache, p->question, DNS_PACKET_RCODE(p), p->answer, DNS_PACKET_ANCOUNT(p), 0, p->family, &p->sender);
 

commit 8300ba218e3cf5049496937be8bce10f22d09bbc
Author: Tom Gundersen <teg at jklm.no>
Date:   Wed Jun 24 18:54:12 2015 +0200

    resolved: pin the server used in a transaction
    
    We want to discover information about the server and use that in when crafting
    packets to be resent.

diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c
index e01e97b..34d4a98 100644
--- a/src/resolve/resolved-dns-scope.c
+++ b/src/resolve/resolved-dns-scope.c
@@ -125,7 +125,8 @@ void dns_scope_next_dns_server(DnsScope *s) {
                 manager_next_dns_server(s->manager);
 }
 
-int dns_scope_emit(DnsScope *s, DnsPacket *p) {
+int dns_scope_emit(DnsScope *s, DnsPacket *p, DnsServer **server) {
+        DnsServer *srv = NULL;
         union in_addr_union addr;
         int ifindex = 0, r;
         int family;
@@ -144,8 +145,6 @@ int dns_scope_emit(DnsScope *s, DnsPacket *p) {
                 mtu = manager_find_mtu(s->manager);
 
         if (s->protocol == DNS_PROTOCOL_DNS) {
-                DnsServer *srv;
-
                 if (DNS_PACKET_QDCOUNT(p) > 1)
                         return -EOPNOTSUPP;
 
@@ -200,10 +199,14 @@ int dns_scope_emit(DnsScope *s, DnsPacket *p) {
         if (r < 0)
                 return r;
 
+        if (server)
+                *server = srv;
+
         return 1;
 }
 
-int dns_scope_tcp_socket(DnsScope *s, int family, const union in_addr_union *address, uint16_t port) {
+int dns_scope_tcp_socket(DnsScope *s, int family, const union in_addr_union *address, uint16_t port, DnsServer **server) {
+        DnsServer *srv = NULL;
         _cleanup_close_ int fd = -1;
         union sockaddr_union sa = {};
         socklen_t salen;
@@ -214,8 +217,6 @@ int dns_scope_tcp_socket(DnsScope *s, int family, const union in_addr_union *add
         assert((family == AF_UNSPEC) == !address);
 
         if (family == AF_UNSPEC) {
-                DnsServer *srv;
-
                 srv = dns_scope_get_dns_server(s);
                 if (!srv)
                         return -ESRCH;
@@ -288,6 +289,9 @@ int dns_scope_tcp_socket(DnsScope *s, int family, const union in_addr_union *add
         if (r < 0 && errno != EINPROGRESS)
                 return -errno;
 
+        if (server)
+                *server = srv;
+
         ret = fd;
         fd = -1;
 
@@ -696,7 +700,7 @@ static int on_conflict_dispatch(sd_event_source *es, usec_t usec, void *userdata
                         return 0;
                 }
 
-                r = dns_scope_emit(scope, p);
+                r = dns_scope_emit(scope, p, NULL);
                 if (r < 0)
                         log_debug_errno(r, "Failed to send conflict packet: %m");
         }
diff --git a/src/resolve/resolved-dns-scope.h b/src/resolve/resolved-dns-scope.h
index cfbde13..f836407 100644
--- a/src/resolve/resolved-dns-scope.h
+++ b/src/resolve/resolved-dns-scope.h
@@ -65,8 +65,8 @@ struct DnsScope {
 int dns_scope_new(Manager *m, DnsScope **ret, Link *l, DnsProtocol p, int family);
 DnsScope* dns_scope_free(DnsScope *s);
 
-int dns_scope_emit(DnsScope *s, DnsPacket *p);
-int dns_scope_tcp_socket(DnsScope *s, int family, const union in_addr_union *address, uint16_t port);
+int dns_scope_emit(DnsScope *s, DnsPacket *p, DnsServer **server);
+int dns_scope_tcp_socket(DnsScope *s, int family, const union in_addr_union *address, uint16_t port, DnsServer **server);
 
 DnsScopeMatch dns_scope_good_domain(DnsScope *s, int ifindex, uint64_t flags, const char *domain);
 int dns_scope_good_key(DnsScope *s, DnsResourceKey *key);
diff --git a/src/resolve/resolved-dns-server.h b/src/resolve/resolved-dns-server.h
index 03013be..06059e8 100644
--- a/src/resolve/resolved-dns-server.h
+++ b/src/resolve/resolved-dns-server.h
@@ -62,4 +62,6 @@ int dns_server_new(
 DnsServer* dns_server_ref(DnsServer *s);
 DnsServer* dns_server_unref(DnsServer *s);
 
+DEFINE_TRIVIAL_CLEANUP_FUNC(DnsServer*, dns_server_unref);
+
 extern const struct hash_ops dns_server_hash_ops;
diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c
index 3f4673d..7fa73cd 100644
--- a/src/resolve/resolved-dns-transaction.c
+++ b/src/resolve/resolved-dns-transaction.c
@@ -39,6 +39,7 @@ DnsTransaction* dns_transaction_free(DnsTransaction *t) {
         dns_packet_unref(t->received);
         dns_answer_unref(t->cached);
 
+        dns_server_unref(t->server);
         dns_stream_free(t->stream);
 
         if (t->scope) {
@@ -237,6 +238,7 @@ static int on_stream_complete(DnsStream *s, int error) {
 }
 
 static int dns_transaction_open_tcp(DnsTransaction *t) {
+        _cleanup_(dns_server_unrefp) DnsServer *server = NULL;
         _cleanup_close_ int fd = -1;
         int r;
 
@@ -246,12 +248,12 @@ static int dns_transaction_open_tcp(DnsTransaction *t) {
                 return 0;
 
         if (t->scope->protocol == DNS_PROTOCOL_DNS)
-                fd = dns_scope_tcp_socket(t->scope, AF_UNSPEC, NULL, 53);
+                fd = dns_scope_tcp_socket(t->scope, AF_UNSPEC, NULL, 53, &server);
         else if (t->scope->protocol == DNS_PROTOCOL_LLMNR) {
 
                 /* When we already received a query to this (but it was truncated), send to its sender address */
                 if (t->received)
-                        fd = dns_scope_tcp_socket(t->scope, t->received->family, &t->received->sender, t->received->sender_port);
+                        fd = dns_scope_tcp_socket(t->scope, t->received->family, &t->received->sender, t->received->sender_port, NULL);
                 else {
                         union in_addr_union address;
                         int family = AF_UNSPEC;
@@ -265,7 +267,7 @@ static int dns_transaction_open_tcp(DnsTransaction *t) {
                         if (r == 0)
                                 return -EINVAL;
 
-                        fd = dns_scope_tcp_socket(t->scope, family, &address, LLMNR_PORT);
+                        fd = dns_scope_tcp_socket(t->scope, family, &address, LLMNR_PORT, NULL);
                 }
         } else
                 return -EAFNOSUPPORT;
@@ -285,6 +287,9 @@ static int dns_transaction_open_tcp(DnsTransaction *t) {
                 return r;
         }
 
+
+        dns_server_unref(t->server);
+        t->server = dns_server_ref(server);
         t->received = dns_packet_unref(t->received);
         t->stream->complete = on_stream_complete;
         t->stream->transaction = t;
@@ -492,6 +497,7 @@ int dns_transaction_go(DnsTransaction *t) {
         }
 
         t->n_attempts++;
+        t->server = dns_server_unref(t->server);
         t->received = dns_packet_unref(t->received);
         t->cached = dns_answer_unref(t->cached);
         t->cached_rcode = 0;
@@ -571,17 +577,20 @@ int dns_transaction_go(DnsTransaction *t) {
                  * always be made via TCP on LLMNR */
                 r = dns_transaction_open_tcp(t);
         } else {
+                DnsServer *server;
+
                 /* Try via UDP, and if that fails due to large size try via TCP */
-                r = dns_scope_emit(t->scope, t->sent);
-                if (r == -EMSGSIZE)
+                r = dns_scope_emit(t->scope, t->sent, &server);
+                if (r >= 0)
+                        t->server = dns_server_ref(server);
+                else if (r == -EMSGSIZE)
                         r = dns_transaction_open_tcp(t);
         }
         if (r == -ESRCH) {
                 /* No servers to send this to? */
                 dns_transaction_complete(t, DNS_TRANSACTION_NO_SERVERS);
                 return 0;
-        }
-        if (r < 0) {
+        } else if (r < 0) {
                 if (t->scope->protocol != DNS_PROTOCOL_DNS) {
                         dns_transaction_complete(t, DNS_TRANSACTION_RESOURCES);
                         return 0;
diff --git a/src/resolve/resolved-dns-transaction.h b/src/resolve/resolved-dns-transaction.h
index f6d539d..42f846e 100644
--- a/src/resolve/resolved-dns-transaction.h
+++ b/src/resolve/resolved-dns-transaction.h
@@ -61,6 +61,9 @@ struct DnsTransaction {
         sd_event_source *timeout_event_source;
         unsigned n_attempts;
 
+        /* the active server */
+        DnsServer *server;
+
         /* TCP connection logic, if we need it */
         DnsStream *stream;
 

commit 73b836e22f6b42308e05df284b90ce2c9cb32af4
Merge: 0a9ccaf fbbf7a9
Author: Daniel Mack <github at zonque.org>
Date:   Tue Jul 14 12:41:29 2015 -0400

    Merge pull request #530 from dvdhrm/resolve-host-dbus
    
    resolve-host: enable dbus-activation


commit 0a9ccafe10dd68bdeaf458816bf87166074cf2f1
Merge: ff89f8b 43f78da
Author: Daniel Mack <github at zonque.org>
Date:   Tue Jul 14 12:03:45 2015 -0400

    Merge pull request #579 from ssahani/tap-vnet-hdr
    
    networkd: tap add support for vnet_hdr


commit 43f78da4ed39fb2ed5c85f8586b4f78409e31bef
Author: Susant Sahani <susant at redhat.com>
Date:   Tue Jul 14 20:48:09 2015 +0530

    man:  add man for tap vnet_hdr

diff --git a/man/systemd.netdev.xml b/man/systemd.netdev.xml
index 01c31c5..ff7b854 100644
--- a/man/systemd.netdev.xml
+++ b/man/systemd.netdev.xml
@@ -563,6 +563,16 @@
         </listitem>
       </varlistentry>
       <varlistentry>
+        <term><varname>VnetHeader=</varname></term>
+        <listitem><para>Takes a boolean argument. Configures
+        IFF_VNET_HDR flag for a tap device. It allows sending
+        and receiving larger Generic Segmentation Offload (GSO)
+        packets. This may increase throughput significantly.
+        Defaults to
+        <literal>no</literal>.</para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
         <term><varname>User=</varname></term>
         <listitem><para>User to grant access to the
         <filename>/dev/net/tun</filename> device.</para>

commit 91b14d6ff362b938a72db17b095ee9903d07381b
Author: Tom Gundersen <teg at jklm.no>
Date:   Wed Jun 24 18:41:46 2015 +0200

    resolved: reference count the dns servers
    
    We want to reference the servers from their active transactions, so make sure
    they stay around as long as the transaction does.

diff --git a/src/resolve/resolved-dns-server.c b/src/resolve/resolved-dns-server.c
index 9a62a63..92e48ae 100644
--- a/src/resolve/resolved-dns-server.c
+++ b/src/resolve/resolved-dns-server.c
@@ -41,6 +41,7 @@ int dns_server_new(
         if (!s)
                 return -ENOMEM;
 
+        s->n_ref = 1;
         s->type = type;
         s->family = family;
         s->address = *in_addr;
@@ -74,33 +75,46 @@ int dns_server_new(
         return 0;
 }
 
-DnsServer* dns_server_free(DnsServer *s)  {
+DnsServer* dns_server_ref(DnsServer *s)  {
         if (!s)
                 return NULL;
 
-        if (s->link) {
-                if (s->type == DNS_SERVER_LINK)
-                        LIST_REMOVE(servers, s->link->dns_servers, s);
+        assert(s->n_ref > 0);
 
-                if (s->link->current_dns_server == s)
-                        link_set_dns_server(s->link, NULL);
-        }
+        s->n_ref ++;
 
-        if (s->manager) {
-                if (s->type == DNS_SERVER_SYSTEM)
-                        LIST_REMOVE(servers, s->manager->dns_servers, s);
-                else if (s->type == DNS_SERVER_FALLBACK)
-                        LIST_REMOVE(servers, s->manager->fallback_dns_servers, s);
+        return s;
+}
+
+static DnsServer* dns_server_free(DnsServer *s)  {
+        if (!s)
+                return NULL;
 
-                if (s->manager->current_dns_server == s)
-                        manager_set_dns_server(s->manager, NULL);
-        }
+        if (s->link && s->link->current_dns_server == s)
+                link_set_dns_server(s->link, NULL);
+
+        if (s->manager && s->manager->current_dns_server == s)
+                manager_set_dns_server(s->manager, NULL);
 
         free(s);
 
         return NULL;
 }
 
+DnsServer* dns_server_unref(DnsServer *s)  {
+        if (!s)
+                return NULL;
+
+        assert(s->n_ref > 0);
+
+        if (s->n_ref == 1)
+                dns_server_free(s);
+        else
+                s->n_ref --;
+
+        return NULL;
+}
+
 static unsigned long dns_server_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) {
         const DnsServer *s = p;
         uint64_t u;
diff --git a/src/resolve/resolved-dns-server.h b/src/resolve/resolved-dns-server.h
index 70ff35b..03013be 100644
--- a/src/resolve/resolved-dns-server.h
+++ b/src/resolve/resolved-dns-server.h
@@ -37,6 +37,8 @@ typedef enum DnsServerType {
 struct DnsServer {
         Manager *manager;
 
+        unsigned n_ref;
+
         DnsServerType type;
 
         Link *link;
@@ -57,6 +59,7 @@ int dns_server_new(
                 int family,
                 const union in_addr_union *address);
 
-DnsServer* dns_server_free(DnsServer *s);
+DnsServer* dns_server_ref(DnsServer *s);
+DnsServer* dns_server_unref(DnsServer *s);
 
 extern const struct hash_ops dns_server_hash_ops;
diff --git a/src/resolve/resolved-link.c b/src/resolve/resolved-link.c
index ff8dc3a..d66b3a8 100644
--- a/src/resolve/resolved-link.c
+++ b/src/resolve/resolved-link.c
@@ -58,7 +58,6 @@ int link_new(Manager *m, Link **ret, int ifindex) {
 }
 
 Link *link_free(Link *l) {
-
         if (!l)
                 return NULL;
 
@@ -68,8 +67,12 @@ Link *link_free(Link *l) {
         if (l->manager)
                 hashmap_remove(l->manager->links, INT_TO_PTR(l->ifindex));
 
-        while (l->dns_servers)
-                dns_server_free(l->dns_servers);
+        while (l->dns_servers) {
+                DnsServer *s = l->dns_servers;
+
+                LIST_REMOVE(servers, l->dns_servers, s);
+                dns_server_unref(s);
+        }
 
         dns_scope_free(l->unicast_scope);
         dns_scope_free(l->llmnr_ipv4_scope);
@@ -182,14 +185,20 @@ static int link_update_dns_servers(Link *l) {
         }
 
         LIST_FOREACH_SAFE(servers, s, nx, l->dns_servers)
-                if (s->marked)
-                        dns_server_free(s);
+                if (s->marked) {
+                        LIST_REMOVE(servers, l->dns_servers, s);
+                        dns_server_unref(s);
+                }
 
         return 0;
 
 clear:
-        while (l->dns_servers)
-                dns_server_free(l->dns_servers);
+        while (l->dns_servers) {
+                s = l->dns_servers;
+
+                LIST_REMOVE(servers, l->dns_servers, s);
+                dns_server_unref(s);
+        }
 
         return r;
 }
diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c
index 6785a2e..e050092 100644
--- a/src/resolve/resolved-manager.c
+++ b/src/resolve/resolved-manager.c
@@ -603,8 +603,10 @@ int manager_read_resolv_conf(Manager *m) {
         }
 
         LIST_FOREACH_SAFE(servers, s, nx, m->dns_servers)
-                if (s->marked)
-                        dns_server_free(s);
+                if (s->marked) {
+                        LIST_REMOVE(servers, m->dns_servers, s);
+                        dns_server_unref(s);
+                }
 
         /* Whenever /etc/resolv.conf changes, start using the first
          * DNS server of it. This is useful to deal with broken
@@ -619,8 +621,12 @@ int manager_read_resolv_conf(Manager *m) {
         return 0;
 
 clear:
-        while (m->dns_servers)
-                dns_server_free(m->dns_servers);
+        while (m->dns_servers) {
+                s = m->dns_servers;
+
+                LIST_REMOVE(servers, m->dns_servers, s);
+                dns_server_unref(s);
+        }
 
         return r;
 }
@@ -1381,15 +1387,25 @@ void manager_verify_all(Manager *m) {
 }
 
 void manager_flush_dns_servers(Manager *m, DnsServerType t) {
+        DnsServer *s;
+
         assert(m);
 
         if (t == DNS_SERVER_SYSTEM)
-                while (m->dns_servers)
-                        dns_server_free(m->dns_servers);
+                while (m->dns_servers) {
+                        s = m->dns_servers;
+
+                        LIST_REMOVE(servers, m->dns_servers, s);
+                        dns_server_unref(s);
+                }
 
         if (t == DNS_SERVER_FALLBACK)
-                while (m->fallback_dns_servers)
-                        dns_server_free(m->fallback_dns_servers);
+                while (m->fallback_dns_servers) {
+                        s = m->fallback_dns_servers;
+
+                        LIST_REMOVE(servers, m->fallback_dns_servers, s);
+                        dns_server_unref(s);
+                }
 }
 
 static const char* const support_table[_SUPPORT_MAX] = {

commit a0166609f782da91710dea9183d1bf138538db37
Author: Tom Gundersen <teg at jklm.no>
Date:   Wed Jun 24 21:22:46 2015 +0200

    resolved: packet - ensure there is space for IP+UDP headers
    
    Currently we only make sure our links can handle the size of the payload witohut
    taking the headers into account.

diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c
index fa0516f..a9cc5ca 100644
--- a/src/resolve/resolved-dns-packet.c
+++ b/src/resolve/resolved-dns-packet.c
@@ -32,10 +32,10 @@ int dns_packet_new(DnsPacket **ret, DnsProtocol protocol, size_t mtu) {
 
         assert(ret);
 
-        if (mtu <= 0)
+        if (mtu <= UDP_PACKET_HEADER_SIZE)
                 a = DNS_PACKET_SIZE_START;
         else
-                a = mtu;
+                a = mtu - UDP_PACKET_HEADER_SIZE;
 
         if (a < DNS_PACKET_HEADER_SIZE)
                 a = DNS_PACKET_HEADER_SIZE;
diff --git a/src/resolve/resolved-dns-packet.h b/src/resolve/resolved-dns-packet.h
index bf998aa..6588ed9 100644
--- a/src/resolve/resolved-dns-packet.h
+++ b/src/resolve/resolved-dns-packet.h
@@ -21,6 +21,8 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
  ***/
 
+#include <netinet/udp.h>
+#include <netinet/ip.h>
 
 #include "macro.h"
 #include "sparse-endian.h"
@@ -53,6 +55,7 @@ struct DnsPacketHeader {
 };
 
 #define DNS_PACKET_HEADER_SIZE sizeof(DnsPacketHeader)
+#define UDP_PACKET_HEADER_SIZE (sizeof(struct iphdr) + sizeof(struct udphdr))
 
 /* The various DNS protocols deviate in how large a packet can grow,
    but the TCP transport has a 16bit size field, hence that appears to
diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c
index 25392d2..e01e97b 100644
--- a/src/resolve/resolved-dns-scope.c
+++ b/src/resolve/resolved-dns-scope.c
@@ -160,7 +160,7 @@ int dns_scope_emit(DnsScope *s, DnsPacket *p) {
                 if (p->size > DNS_PACKET_UNICAST_SIZE_MAX)
                         return -EMSGSIZE;
 
-                if (p->size > mtu)
+                if (p->size + UDP_PACKET_HEADER_SIZE > mtu)
                         return -EMSGSIZE;
 
                 if (family == AF_INET)

commit f5f07dbf06f6df9d12e092c05ad8cfbe244d203f
Author: Susant Sahani <ssahani at gmail.com>
Date:   Tue Jul 14 13:55:52 2015 +0530

    networkd: tap add support for vnet_hdr
    
     This patch adds support to configure IFF_VNET_HDR flag
    for a tap device. It allows whether sending and receiving
    large pass larger (GSO) packets. This greatly increases the
    achievable throughput.

diff --git a/src/network/networkd-netdev-gperf.gperf b/src/network/networkd-netdev-gperf.gperf
index 66ed2e0..010c106 100644
--- a/src/network/networkd-netdev-gperf.gperf
+++ b/src/network/networkd-netdev-gperf.gperf
@@ -59,6 +59,7 @@ Tun.Group,                   config_parse_string,                0,
 Tap.OneQueue,                config_parse_bool,                  0,                             offsetof(TunTap, one_queue)
 Tap.MultiQueue,              config_parse_bool,                  0,                             offsetof(TunTap, multi_queue)
 Tap.PacketInfo,              config_parse_bool,                  0,                             offsetof(TunTap, packet_info)
+Tap.VnetHeader,              config_parse_bool,                  0,                             offsetof(TunTap, vnet_hdr)
 Tap.User,                    config_parse_string,                0,                             offsetof(TunTap, user_name)
 Tap.Group,                   config_parse_string,                0,                             offsetof(TunTap, group_name)
 Bond.Mode,                   config_parse_bond_mode,             0,                             offsetof(Bond, mode)
diff --git a/src/network/networkd-netdev-tuntap.c b/src/network/networkd-netdev-tuntap.c
index 378312f..ba84e80 100644
--- a/src/network/networkd-netdev-tuntap.c
+++ b/src/network/networkd-netdev-tuntap.c
@@ -51,6 +51,9 @@ static int netdev_fill_tuntap_message(NetDev *netdev, struct ifreq *ifr) {
         if (t->multi_queue)
                 ifr->ifr_flags |= IFF_MULTI_QUEUE;
 
+        if (t->vnet_hdr)
+                ifr->ifr_flags |= IFF_VNET_HDR;
+
         strncpy(ifr->ifr_name, netdev->ifname, IFNAMSIZ-1);
 
         return 0;
diff --git a/src/network/networkd-netdev-tuntap.h b/src/network/networkd-netdev-tuntap.h
index b804875..29f8bb0 100644
--- a/src/network/networkd-netdev-tuntap.h
+++ b/src/network/networkd-netdev-tuntap.h
@@ -33,6 +33,7 @@ struct TunTap {
         bool one_queue;
         bool multi_queue;
         bool packet_info;
+        bool vnet_hdr;
 };
 
 extern const NetDevVTable tun_vtable;

commit 1bf968f36393666f2c57953b1748e6219c027dee
Author: Tom Gundersen <teg at jklm.no>
Date:   Mon Jul 13 00:21:50 2015 +0200

    resolved: rr - print DNSKEY and RRSIG in base64
    
    As mandated by RFC4034.

diff --git a/TODO b/TODO
index 2904e2b..17295fe 100644
--- a/TODO
+++ b/TODO
@@ -342,7 +342,6 @@ Features:
   - put networkd events and rtnl events at a higher priority, so that
     we always process them before we process client requests
   - DNSSEC
-        - use base64 for key presentation?
         - add display of private key types (http://tools.ietf.org/html/rfc4034#appendix-A.1.1)?
         - add nice formatting of DNS timestamps
   - DNS
diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c
index c1818ee..f46f868 100644
--- a/src/resolve/resolved-dns-rr.c
+++ b/src/resolve/resolved-dns-rr.c
@@ -608,7 +608,7 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
 
                 alg = dnssec_algorithm_to_string(rr->dnskey.algorithm);
 
-                t = hexmem(rr->dnskey.key, rr->dnskey.key_size);
+                t = base64mem(rr->dnskey.key, rr->dnskey.key_size);
                 if (!t)
                         return -ENOMEM;
 
@@ -629,7 +629,7 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
                 type = dns_type_to_string(rr->rrsig.type_covered);
                 alg = dnssec_algorithm_to_string(rr->rrsig.algorithm);
 
-                t = hexmem(rr->rrsig.signature, rr->rrsig.signature_size);
+                t = base64mem(rr->rrsig.signature, rr->rrsig.signature_size);
                 if (!t)
                         return -ENOMEM;
 

commit ff89f8b917a83a3fc0dc3ad0961c3bc953f78e8f
Merge: f7c7350 818ef44
Author: Tom Gundersen <teg at jklm.no>
Date:   Mon Jul 13 19:30:30 2015 +0200

    Merge pull request #576 from zonque/resolved-cleanups
    
    resolved: assorted cleanups


commit 818ef443f0281acd952878cdb01cbdaa42195912
Author: Daniel Mack <daniel at zonque.org>
Date:   Sat Jul 11 12:37:17 2015 -0400

    resolved: make LLMNR checks conditional
    
    Make all LLMNR related packet inspections conditional to p->protocol.
    Use switch-case statements while at it, which will make future additions
    more readable.

diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c
index 47cc975..fa0516f 100644
--- a/src/resolve/resolved-dns-packet.c
+++ b/src/resolve/resolved-dns-packet.c
@@ -166,10 +166,17 @@ int dns_packet_validate_reply(DnsPacket *p) {
         if (DNS_PACKET_OPCODE(p) != 0)
                 return -EBADMSG;
 
-        /* RFC 4795, Section 2.1.1. says to discard all replies with QDCOUNT != 1 */
-        if (p->protocol == DNS_PROTOCOL_LLMNR &&
-            DNS_PACKET_QDCOUNT(p) != 1)
-                return -EBADMSG;
+        switch (p->protocol) {
+        case DNS_PROTOCOL_LLMNR:
+                /* RFC 4795, Section 2.1.1. says to discard all replies with QDCOUNT != 1 */
+                if (DNS_PACKET_QDCOUNT(p) != 1)
+                        return -EBADMSG;
+
+                break;
+
+        default:
+                break;
+        }
 
         return 1;
 }
@@ -192,18 +199,25 @@ int dns_packet_validate_query(DnsPacket *p) {
         if (DNS_PACKET_TC(p))
                 return -EBADMSG;
 
-        /* RFC 4795, Section 2.1.1. says to discard all queries with QDCOUNT != 1 */
-        if (p->protocol == DNS_PROTOCOL_LLMNR &&
-            DNS_PACKET_QDCOUNT(p) != 1)
-                return -EBADMSG;
+        switch (p->protocol) {
+        case DNS_PROTOCOL_LLMNR:
+                /* RFC 4795, Section 2.1.1. says to discard all queries with QDCOUNT != 1 */
+                if (DNS_PACKET_QDCOUNT(p) != 1)
+                        return -EBADMSG;
 
-        /* RFC 4795, Section 2.1.1. says to discard all queries with ANCOUNT != 0 */
-        if (DNS_PACKET_ANCOUNT(p) > 0)
-                return -EBADMSG;
+                /* RFC 4795, Section 2.1.1. says to discard all queries with ANCOUNT != 0 */
+                if (DNS_PACKET_ANCOUNT(p) > 0)
+                        return -EBADMSG;
 
-        /* RFC 4795, Section 2.1.1. says to discard all queries with NSCOUNT != 0 */
-        if (DNS_PACKET_NSCOUNT(p) > 0)
-                return -EBADMSG;
+                /* RFC 4795, Section 2.1.1. says to discard all queries with NSCOUNT != 0 */
+                if (DNS_PACKET_NSCOUNT(p) > 0)
+                        return -EBADMSG;
+
+                break;
+
+        default:
+                break;
+        }
 
         return 1;
 }

commit 8b757a38611006a751c90933d1810cccaa47e1af
Author: Daniel Mack <daniel at zonque.org>
Date:   Fri Jul 10 20:35:16 2015 -0400

    resolved: separate LLMNR specific header bits
    
    The C and T bits in the DNS packet header definitions are specific to LLMNR.
    In regular DNS, they are called AA and RD instead. Reflect that by calling
    the macros accordingly, and alias LLMNR specific macros.
    
    While at it, define RA, AD and CD getters as well.

diff --git a/src/resolve/resolved-dns-packet.h b/src/resolve/resolved-dns-packet.h
index c586738..bf998aa 100644
--- a/src/resolve/resolved-dns-packet.h
+++ b/src/resolve/resolved-dns-packet.h
@@ -99,10 +99,18 @@ static inline uint8_t* DNS_PACKET_DATA(DnsPacket *p) {
 #define DNS_PACKET_ID(p) DNS_PACKET_HEADER(p)->id
 #define DNS_PACKET_QR(p) ((be16toh(DNS_PACKET_HEADER(p)->flags) >> 15) & 1)
 #define DNS_PACKET_OPCODE(p) ((be16toh(DNS_PACKET_HEADER(p)->flags) >> 11) & 15)
-#define DNS_PACKET_RCODE(p) (be16toh(DNS_PACKET_HEADER(p)->flags) & 15)
+#define DNS_PACKET_AA(p) ((be16toh(DNS_PACKET_HEADER(p)->flags) >> 10) & 1)
 #define DNS_PACKET_TC(p) ((be16toh(DNS_PACKET_HEADER(p)->flags) >> 9) & 1)
-#define DNS_PACKET_C(p) ((be16toh(DNS_PACKET_HEADER(p)->flags) >> 10) & 1)
-#define DNS_PACKET_T(p) ((be16toh(DNS_PACKET_HEADER(p)->flags) >> 8) & 1)
+#define DNS_PACKET_RD(p) ((be16toh(DNS_PACKET_HEADER(p)->flags) >> 8) & 1)
+#define DNS_PACKET_RA(p) ((be16toh(DNS_PACKET_HEADER(p)->flags) >> 7) & 1)
+#define DNS_PACKET_AD(p) ((be16toh(DNS_PACKET_HEADER(p)->flags) >> 5) & 1)
+#define DNS_PACKET_CD(p) ((be16toh(DNS_PACKET_HEADER(p)->flags) >> 4) & 1)
+#define DNS_PACKET_RCODE(p) (be16toh(DNS_PACKET_HEADER(p)->flags) & 15)
+
+/* LLMNR defines some bits differently */
+#define DNS_PACKET_LLMNR_C(p) DNS_PACKET_AA(p)
+#define DNS_PACKET_LLMNR_T(p) DNS_PACKET_RD(p)
+
 #define DNS_PACKET_QDCOUNT(p) be16toh(DNS_PACKET_HEADER(p)->qdcount)
 #define DNS_PACKET_ANCOUNT(p) be16toh(DNS_PACKET_HEADER(p)->ancount)
 #define DNS_PACKET_NSCOUNT(p) be16toh(DNS_PACKET_HEADER(p)->nscount)
diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c
index 596181f..25392d2 100644
--- a/src/resolve/resolved-dns-scope.c
+++ b/src/resolve/resolved-dns-scope.c
@@ -547,7 +547,7 @@ void dns_scope_process_query(DnsScope *s, DnsStream *stream, DnsPacket *p) {
                 return;
         }
 
-        if (DNS_PACKET_C(p)) {
+        if (DNS_PACKET_LLMNR_C(p)) {
                 /* Somebody notified us about a possible conflict */
                 dns_scope_verify_conflicts(s, p);
                 return;
@@ -761,10 +761,10 @@ void dns_scope_check_conflicts(DnsScope *scope, DnsPacket *p) {
         if (DNS_PACKET_RRCOUNT(p) <= 0)
                 return;
 
-        if (DNS_PACKET_C(p) != 0)
+        if (DNS_PACKET_LLMNR_C(p) != 0)
                 return;
 
-        if (DNS_PACKET_T(p) != 0)
+        if (DNS_PACKET_LLMNR_T(p) != 0)
                 return;
 
         if (manager_our_packet(scope->manager, p))
diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c
index 21247e8..3f4673d 100644
--- a/src/resolve/resolved-dns-transaction.c
+++ b/src/resolve/resolved-dns-transaction.c
@@ -324,7 +324,7 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) {
                 /* Tentative packets are not full responses but still
                  * useful for identifying uniqueness conflicts during
                  * probing. */
-                if (DNS_PACKET_T(p)) {
+                if (DNS_PACKET_LLMNR_T(p)) {
                         dns_transaction_tentative(t, p);
                         return;
                 }

commit 22a37591ede1e9d5f325d6f10495cc91b40b775f
Author: Daniel Mack <daniel at zonque.org>
Date:   Fri Jul 10 15:28:09 2015 -0400

    resolved: use a #define for LLMNR port
    
    De-duplicate some magic numbers.

diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c
index cc7e268..596181f 100644
--- a/src/resolve/resolved-dns-scope.c
+++ b/src/resolve/resolved-dns-scope.c
@@ -181,7 +181,7 @@ int dns_scope_emit(DnsScope *s, DnsPacket *p) {
                         return -EBUSY;
 
                 family = s->family;
-                port = 5355;
+                port = LLMNR_PORT;
 
                 if (family == AF_INET) {
                         addr.in = LLMNR_MULTICAST_IPV4_ADDRESS;
diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c
index 2149389..21247e8 100644
--- a/src/resolve/resolved-dns-transaction.c
+++ b/src/resolve/resolved-dns-transaction.c
@@ -21,6 +21,7 @@
 
 #include "af-list.h"
 
+#include "resolved-llmnr.h"
 #include "resolved-dns-transaction.h"
 #include "random-util.h"
 
@@ -264,7 +265,7 @@ static int dns_transaction_open_tcp(DnsTransaction *t) {
                         if (r == 0)
                                 return -EINVAL;
 
-                        fd = dns_scope_tcp_socket(t->scope, family, &address, 5355);
+                        fd = dns_scope_tcp_socket(t->scope, family, &address, LLMNR_PORT);
                 }
         } else
                 return -EAFNOSUPPORT;
diff --git a/src/resolve/resolved-llmnr.c b/src/resolve/resolved-llmnr.c
index ee9a416..8afaf8d 100644
--- a/src/resolve/resolved-llmnr.c
+++ b/src/resolve/resolved-llmnr.c
@@ -124,7 +124,7 @@ static int on_llmnr_packet(sd_event_source *s, int fd, uint32_t revents, void *u
 int manager_llmnr_ipv4_udp_fd(Manager *m) {
         union sockaddr_union sa = {
                 .in.sin_family = AF_INET,
-                .in.sin_port = htobe16(5355),
+                .in.sin_port = htobe16(LLMNR_PORT),
         };
         static const int one = 1, pmtu = IP_PMTUDISC_DONT, ttl = 255;
         int r;
@@ -202,7 +202,7 @@ fail:
 int manager_llmnr_ipv6_udp_fd(Manager *m) {
         union sockaddr_union sa = {
                 .in6.sin6_family = AF_INET6,
-                .in6.sin6_port = htobe16(5355),
+                .in6.sin6_port = htobe16(LLMNR_PORT),
         };
         static const int one = 1, ttl = 255;
         int r;
@@ -330,7 +330,7 @@ static int on_llmnr_stream(sd_event_source *s, int fd, uint32_t revents, void *u
 int manager_llmnr_ipv4_tcp_fd(Manager *m) {
         union sockaddr_union sa = {
                 .in.sin_family = AF_INET,
-                .in.sin_port = htobe16(5355),
+                .in.sin_port = htobe16(LLMNR_PORT),
         };
         static const int one = 1, pmtu = IP_PMTUDISC_DONT;
         int r;
@@ -402,7 +402,7 @@ fail:
 int manager_llmnr_ipv6_tcp_fd(Manager *m) {
         union sockaddr_union sa = {
                 .in6.sin6_family = AF_INET6,
-                .in6.sin6_port = htobe16(5355),
+                .in6.sin6_port = htobe16(LLMNR_PORT),
         };
         static const int one = 1;
         int r;
diff --git a/src/resolve/resolved-llmnr.h b/src/resolve/resolved-llmnr.h
index 6406440..d489d48 100644
--- a/src/resolve/resolved-llmnr.h
+++ b/src/resolve/resolved-llmnr.h
@@ -23,6 +23,8 @@
 
 #include "resolved-manager.h"
 
+#define LLMNR_PORT 5355
+
 int manager_llmnr_ipv4_udp_fd(Manager *m);
 int manager_llmnr_ipv6_udp_fd(Manager *m);
 int manager_llmnr_ipv4_tcp_fd(Manager *m);

commit 5f402ae84bbc08fe8de5682e371b3f66c387da52
Author: Daniel Mack <daniel at zonque.org>
Date:   Fri Jul 10 15:02:38 2015 -0400

    resolved: move LLMNR related functions into separate file

diff --git a/Makefile.am b/Makefile.am
index e178bdc..c038fed 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -5102,6 +5102,8 @@ systemd_resolved_SOURCES = \
 	src/resolve/resolved-bus.h \
 	src/resolve/resolved-link.h \
 	src/resolve/resolved-link.c \
+	src/resolve/resolved-llmnr.h \
+	src/resolve/resolved-llmnr.c \
 	src/resolve/resolved-def.h \
 	src/resolve/resolved-dns-rr.h \
 	src/resolve/resolved-dns-rr.c \
diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c
index c25ac22..cc7e268 100644
--- a/src/resolve/resolved-dns-scope.c
+++ b/src/resolve/resolved-dns-scope.c
@@ -28,6 +28,7 @@
 #include "random-util.h"
 #include "hostname-util.h"
 #include "dns-domain.h"
+#include "resolved-llmnr.h"
 #include "resolved-dns-scope.h"
 
 #define MULTICAST_RATELIMIT_INTERVAL_USEC (1*USEC_PER_SEC)
diff --git a/src/resolve/resolved-llmnr.c b/src/resolve/resolved-llmnr.c
new file mode 100644
index 0000000..ee9a416
--- /dev/null
+++ b/src/resolve/resolved-llmnr.c
@@ -0,0 +1,473 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2014 Tom Gundersen <teg at jklm.no>
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+ ***/
+
+#include <resolv.h>
+#include <netinet/in.h>
+
+#include "resolved-manager.h"
+#include "resolved-llmnr.h"
+
+void manager_llmnr_stop(Manager *m) {
+        assert(m);
+
+        m->llmnr_ipv4_udp_event_source = sd_event_source_unref(m->llmnr_ipv4_udp_event_source);
+        m->llmnr_ipv4_udp_fd = safe_close(m->llmnr_ipv4_udp_fd);
+
+        m->llmnr_ipv6_udp_event_source = sd_event_source_unref(m->llmnr_ipv6_udp_event_source);
+        m->llmnr_ipv6_udp_fd = safe_close(m->llmnr_ipv6_udp_fd);
+
+        m->llmnr_ipv4_tcp_event_source = sd_event_source_unref(m->llmnr_ipv4_tcp_event_source);
+        m->llmnr_ipv4_tcp_fd = safe_close(m->llmnr_ipv4_tcp_fd);
+
+        m->llmnr_ipv6_tcp_event_source = sd_event_source_unref(m->llmnr_ipv6_tcp_event_source);
+        m->llmnr_ipv6_tcp_fd = safe_close(m->llmnr_ipv6_tcp_fd);
+}
+
+int manager_llmnr_start(Manager *m) {
+        int r;
+
+        assert(m);
+
+        if (m->llmnr_support == SUPPORT_NO)
+                return 0;
+
+        r = manager_llmnr_ipv4_udp_fd(m);
+        if (r == -EADDRINUSE)
+                goto eaddrinuse;
+        if (r < 0)
+                return r;
+
+        r = manager_llmnr_ipv4_tcp_fd(m);
+        if (r == -EADDRINUSE)
+                goto eaddrinuse;
+        if (r < 0)
+                return r;
+
+        if (socket_ipv6_is_supported()) {
+                r = manager_llmnr_ipv6_udp_fd(m);
+                if (r == -EADDRINUSE)
+                        goto eaddrinuse;
+                if (r < 0)
+                        return r;
+
+                r = manager_llmnr_ipv6_tcp_fd(m);
+                if (r == -EADDRINUSE)
+                        goto eaddrinuse;
+                if (r < 0)
+                        return r;
+        }
+
+        return 0;
+
+eaddrinuse:
+        log_warning("There appears to be another LLMNR responder running. Turning off LLMNR support.");
+        m->llmnr_support = SUPPORT_NO;
+        manager_llmnr_stop(m);
+
+        return 0;
+}
+
+static int on_llmnr_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
+        _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
+        DnsTransaction *t = NULL;
+        Manager *m = userdata;
+        DnsScope *scope;
+        int r;
+
+        r = manager_recv(m, fd, DNS_PROTOCOL_LLMNR, &p);
+        if (r <= 0)
+                return r;
+
+        scope = manager_find_scope(m, p);
+        if (!scope) {
+                log_warning("Got LLMNR UDP packet on unknown scope. Ignoring.");
+                return 0;
+        }
+
+        if (dns_packet_validate_reply(p) > 0) {
+                log_debug("Got LLMNR reply packet for id %u", DNS_PACKET_ID(p));
+
+                dns_scope_check_conflicts(scope, p);
+
+                t = hashmap_get(m->dns_transactions, UINT_TO_PTR(DNS_PACKET_ID(p)));
+                if (t)
+                        dns_transaction_process_reply(t, p);
+
+        } else if (dns_packet_validate_query(p) > 0)  {
+                log_debug("Got LLMNR query packet for id %u", DNS_PACKET_ID(p));
+
+                dns_scope_process_query(scope, NULL, p);
+        } else
+                log_debug("Invalid LLMNR UDP packet.");
+
+        return 0;
+}
+
+int manager_llmnr_ipv4_udp_fd(Manager *m) {
+        union sockaddr_union sa = {
+                .in.sin_family = AF_INET,
+                .in.sin_port = htobe16(5355),
+        };
+        static const int one = 1, pmtu = IP_PMTUDISC_DONT, ttl = 255;
+        int r;
+
+        assert(m);
+
+        if (m->llmnr_ipv4_udp_fd >= 0)
+                return m->llmnr_ipv4_udp_fd;
+
+        m->llmnr_ipv4_udp_fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
+        if (m->llmnr_ipv4_udp_fd < 0)
+                return -errno;
+
+        /* RFC 4795, section 2.5 recommends setting the TTL of UDP packets to 255. */
+        r = setsockopt(m->llmnr_ipv4_udp_fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
+        if (r < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        r = setsockopt(m->llmnr_ipv4_udp_fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl));
+        if (r < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        r = setsockopt(m->llmnr_ipv4_udp_fd, IPPROTO_IP, IP_MULTICAST_LOOP, &one, sizeof(one));
+        if (r < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        r = setsockopt(m->llmnr_ipv4_udp_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
+        if (r < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        r = setsockopt(m->llmnr_ipv4_udp_fd, IPPROTO_IP, IP_PKTINFO, &one, sizeof(one));
+        if (r < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        r = setsockopt(m->llmnr_ipv4_udp_fd, IPPROTO_IP, IP_RECVTTL, &one, sizeof(one));
+        if (r < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        /* Disable Don't-Fragment bit in the IP header */
+        r = setsockopt(m->llmnr_ipv4_udp_fd, IPPROTO_IP, IP_MTU_DISCOVER, &pmtu, sizeof(pmtu));
+        if (r < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        r = bind(m->llmnr_ipv4_udp_fd, &sa.sa, sizeof(sa.in));
+        if (r < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        r = sd_event_add_io(m->event, &m->llmnr_ipv4_udp_event_source, m->llmnr_ipv4_udp_fd, EPOLLIN, on_llmnr_packet, m);
+        if (r < 0)
+                goto fail;
+
+        return m->llmnr_ipv4_udp_fd;
+
+fail:
+        m->llmnr_ipv4_udp_fd = safe_close(m->llmnr_ipv4_udp_fd);
+        return r;
+}
+
+int manager_llmnr_ipv6_udp_fd(Manager *m) {
+        union sockaddr_union sa = {
+                .in6.sin6_family = AF_INET6,
+                .in6.sin6_port = htobe16(5355),
+        };
+        static const int one = 1, ttl = 255;
+        int r;
+
+        assert(m);
+
+        if (m->llmnr_ipv6_udp_fd >= 0)
+                return m->llmnr_ipv6_udp_fd;
+
+        m->llmnr_ipv6_udp_fd = socket(AF_INET6, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
+        if (m->llmnr_ipv6_udp_fd < 0)
+                return -errno;
+
+        r = setsockopt(m->llmnr_ipv6_udp_fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl));
+        if (r < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        /* RFC 4795, section 2.5 recommends setting the TTL of UDP packets to 255. */
+        r = setsockopt(m->llmnr_ipv6_udp_fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &ttl, sizeof(ttl));
+        if (r < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        r = setsockopt(m->llmnr_ipv6_udp_fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &one, sizeof(one));
+        if (r < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        r = setsockopt(m->llmnr_ipv6_udp_fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
+        if (r < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        r = setsockopt(m->llmnr_ipv6_udp_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
+        if (r < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        r = setsockopt(m->llmnr_ipv6_udp_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one));
+        if (r < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        r = setsockopt(m->llmnr_ipv6_udp_fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &one, sizeof(one));
+        if (r < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        r = bind(m->llmnr_ipv6_udp_fd, &sa.sa, sizeof(sa.in6));
+        if (r < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        r = sd_event_add_io(m->event, &m->llmnr_ipv6_udp_event_source, m->llmnr_ipv6_udp_fd, EPOLLIN, on_llmnr_packet, m);
+        if (r < 0)  {
+                r = -errno;
+                goto fail;
+        }
+
+        return m->llmnr_ipv6_udp_fd;
+
+fail:
+        m->llmnr_ipv6_udp_fd = safe_close(m->llmnr_ipv6_udp_fd);
+        return r;
+}
+
+static int on_llmnr_stream_packet(DnsStream *s) {
+        DnsScope *scope;
+
+        assert(s);
+
+        scope = manager_find_scope(s->manager, s->read_packet);
+        if (!scope) {
+                log_warning("Got LLMNR TCP packet on unknown scope. Ignroing.");
+                return 0;
+        }
+
+        if (dns_packet_validate_query(s->read_packet) > 0) {
+                log_debug("Got query packet for id %u", DNS_PACKET_ID(s->read_packet));
+
+                dns_scope_process_query(scope, s, s->read_packet);
+
+                /* If no reply packet was set, we free the stream */
+                if (s->write_packet)
+                        return 0;
+        } else
+                log_debug("Invalid LLMNR TCP packet.");
+
+        dns_stream_free(s);
+        return 0;
+}
+
+static int on_llmnr_stream(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
+        DnsStream *stream;
+        Manager *m = userdata;
+        int cfd, r;
+
+        cfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
+        if (cfd < 0) {
+                if (errno == EAGAIN || errno == EINTR)
+                        return 0;
+
+                return -errno;
+        }
+
+        r = dns_stream_new(m, &stream, DNS_PROTOCOL_LLMNR, cfd);
+        if (r < 0) {
+                safe_close(cfd);
+                return r;
+        }
+
+        stream->on_packet = on_llmnr_stream_packet;
+        return 0;
+}
+
+int manager_llmnr_ipv4_tcp_fd(Manager *m) {
+        union sockaddr_union sa = {
+                .in.sin_family = AF_INET,
+                .in.sin_port = htobe16(5355),
+        };
+        static const int one = 1, pmtu = IP_PMTUDISC_DONT;
+        int r;
+
+        assert(m);
+
+        if (m->llmnr_ipv4_tcp_fd >= 0)
+                return m->llmnr_ipv4_tcp_fd;
+
+        m->llmnr_ipv4_tcp_fd = socket(AF_INET, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
+        if (m->llmnr_ipv4_tcp_fd < 0)
+                return -errno;
+
+        /* RFC 4795, section 2.5. requires setting the TTL of TCP streams to 1 */
+        r = setsockopt(m->llmnr_ipv4_tcp_fd, IPPROTO_IP, IP_TTL, &one, sizeof(one));
+        if (r < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        r = setsockopt(m->llmnr_ipv4_tcp_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
+        if (r < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        r = setsockopt(m->llmnr_ipv4_tcp_fd, IPPROTO_IP, IP_PKTINFO, &one, sizeof(one));
+        if (r < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        r = setsockopt(m->llmnr_ipv4_tcp_fd, IPPROTO_IP, IP_RECVTTL, &one, sizeof(one));
+        if (r < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        /* Disable Don't-Fragment bit in the IP header */
+        r = setsockopt(m->llmnr_ipv4_tcp_fd, IPPROTO_IP, IP_MTU_DISCOVER, &pmtu, sizeof(pmtu));
+        if (r < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        r = bind(m->llmnr_ipv4_tcp_fd, &sa.sa, sizeof(sa.in));
+        if (r < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        r = listen(m->llmnr_ipv4_tcp_fd, SOMAXCONN);
+        if (r < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        r = sd_event_add_io(m->event, &m->llmnr_ipv4_tcp_event_source, m->llmnr_ipv4_tcp_fd, EPOLLIN, on_llmnr_stream, m);
+        if (r < 0)
+                goto fail;
+
+        return m->llmnr_ipv4_tcp_fd;
+
+fail:
+        m->llmnr_ipv4_tcp_fd = safe_close(m->llmnr_ipv4_tcp_fd);
+        return r;
+}
+
+int manager_llmnr_ipv6_tcp_fd(Manager *m) {
+        union sockaddr_union sa = {
+                .in6.sin6_family = AF_INET6,
+                .in6.sin6_port = htobe16(5355),
+        };
+        static const int one = 1;
+        int r;
+
+        assert(m);
+
+        if (m->llmnr_ipv6_tcp_fd >= 0)
+                return m->llmnr_ipv6_tcp_fd;
+
+        m->llmnr_ipv6_tcp_fd = socket(AF_INET6, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
+        if (m->llmnr_ipv6_tcp_fd < 0)
+                return -errno;
+
+        /* RFC 4795, section 2.5. requires setting the TTL of TCP streams to 1 */
+        r = setsockopt(m->llmnr_ipv6_tcp_fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &one, sizeof(one));
+        if (r < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        r = setsockopt(m->llmnr_ipv6_tcp_fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
+        if (r < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        r = setsockopt(m->llmnr_ipv6_tcp_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
+        if (r < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        r = setsockopt(m->llmnr_ipv6_tcp_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one));
+        if (r < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        r = setsockopt(m->llmnr_ipv6_tcp_fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &one, sizeof(one));
+        if (r < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        r = bind(m->llmnr_ipv6_tcp_fd, &sa.sa, sizeof(sa.in6));
+        if (r < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        r = listen(m->llmnr_ipv6_tcp_fd, SOMAXCONN);
+        if (r < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        r = sd_event_add_io(m->event, &m->llmnr_ipv6_tcp_event_source, m->llmnr_ipv6_tcp_fd, EPOLLIN, on_llmnr_stream, m);
+        if (r < 0)  {
+                r = -errno;
+                goto fail;
+        }
+
+        return m->llmnr_ipv6_tcp_fd;
+
+fail:
+        m->llmnr_ipv6_tcp_fd = safe_close(m->llmnr_ipv6_tcp_fd);
+        return r;
+}
diff --git a/src/resolve/resolved-llmnr.h b/src/resolve/resolved-llmnr.h
new file mode 100644
index 0000000..6406440
--- /dev/null
+++ b/src/resolve/resolved-llmnr.h
@@ -0,0 +1,32 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+  This file is part of systemd.
+
+  Copyright 2014 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "resolved-manager.h"
+
+int manager_llmnr_ipv4_udp_fd(Manager *m);
+int manager_llmnr_ipv6_udp_fd(Manager *m);
+int manager_llmnr_ipv4_tcp_fd(Manager *m);
+int manager_llmnr_ipv6_tcp_fd(Manager *m);
+
+void manager_llmnr_stop(Manager *m);
+int manager_llmnr_start(Manager *m);
diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c
index dee5e61..6785a2e 100644
--- a/src/resolve/resolved-manager.c
+++ b/src/resolve/resolved-manager.c
@@ -38,6 +38,7 @@
 #include "resolved-conf.h"
 #include "resolved-bus.h"
 #include "resolved-manager.h"
+#include "resolved-llmnr.h"
 
 #define SEND_TIMEOUT_USEC (200 * USEC_PER_MSEC)
 
@@ -393,66 +394,6 @@ static int manager_watch_hostname(Manager *m) {
         return 0;
 }
 
-static void manager_llmnr_stop(Manager *m) {
-        assert(m);
-
-        m->llmnr_ipv4_udp_event_source = sd_event_source_unref(m->llmnr_ipv4_udp_event_source);
-        m->llmnr_ipv4_udp_fd = safe_close(m->llmnr_ipv4_udp_fd);
-
-        m->llmnr_ipv6_udp_event_source = sd_event_source_unref(m->llmnr_ipv6_udp_event_source);
-        m->llmnr_ipv6_udp_fd = safe_close(m->llmnr_ipv6_udp_fd);
-
-        m->llmnr_ipv4_tcp_event_source = sd_event_source_unref(m->llmnr_ipv4_tcp_event_source);
-        m->llmnr_ipv4_tcp_fd = safe_close(m->llmnr_ipv4_tcp_fd);
-
-        m->llmnr_ipv6_tcp_event_source = sd_event_source_unref(m->llmnr_ipv6_tcp_event_source);
-        m->llmnr_ipv6_tcp_fd = safe_close(m->llmnr_ipv6_tcp_fd);
-}
-
-static int manager_llmnr_start(Manager *m) {
-        int r;
-
-        assert(m);
-
-        if (m->llmnr_support == SUPPORT_NO)
-                return 0;
-
-        r = manager_llmnr_ipv4_udp_fd(m);
-        if (r == -EADDRINUSE)
-                goto eaddrinuse;
-        if (r < 0)
-                return r;
-
-        r = manager_llmnr_ipv4_tcp_fd(m);
-        if (r == -EADDRINUSE)
-                goto eaddrinuse;
-        if (r < 0)
-                return r;
-
-        if (socket_ipv6_is_supported()) {
-                r = manager_llmnr_ipv6_udp_fd(m);
-                if (r == -EADDRINUSE)
-                        goto eaddrinuse;
-                if (r < 0)
-                        return r;
-
-                r = manager_llmnr_ipv6_tcp_fd(m);
-                if (r == -EADDRINUSE)
-                        goto eaddrinuse;
-                if (r < 0)
-                        return r;
-        }
-
-        return 0;
-
-eaddrinuse:
-        log_warning("There appears to be another LLMNR responder running. Turning off LLMNR support.");
-        m->llmnr_support = SUPPORT_NO;
-        manager_llmnr_stop(m);
-
-        return 0;
-}
-
 int manager_new(Manager **ret) {
         _cleanup_(manager_freep) Manager *m = NULL;
         int r;
@@ -1316,393 +1257,6 @@ uint32_t manager_find_mtu(Manager *m) {
         return mtu;
 }
 
-static int on_llmnr_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
-        _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
-        DnsTransaction *t = NULL;
-        Manager *m = userdata;
-        DnsScope *scope;
-        int r;
-
-        r = manager_recv(m, fd, DNS_PROTOCOL_LLMNR, &p);
-        if (r <= 0)
-                return r;
-
-        scope = manager_find_scope(m, p);
-        if (!scope) {
-                log_warning("Got LLMNR UDP packet on unknown scope. Ignoring.");
-                return 0;
-        }
-
-        if (dns_packet_validate_reply(p) > 0) {
-                log_debug("Got reply packet for id %u", DNS_PACKET_ID(p));
-
-                dns_scope_check_conflicts(scope, p);
-
-                t = hashmap_get(m->dns_transactions, UINT_TO_PTR(DNS_PACKET_ID(p)));
-                if (t)
-                        dns_transaction_process_reply(t, p);
-
-        } else if (dns_packet_validate_query(p) > 0)  {
-                log_debug("Got query packet for id %u", DNS_PACKET_ID(p));
-
-                dns_scope_process_query(scope, NULL, p);
-        } else
-                log_debug("Invalid LLMNR UDP packet.");
-
-        return 0;
-}
-
-int manager_llmnr_ipv4_udp_fd(Manager *m) {
-        union sockaddr_union sa = {
-                .in.sin_family = AF_INET,
-                .in.sin_port = htobe16(5355),
-        };
-        static const int one = 1, pmtu = IP_PMTUDISC_DONT, ttl = 255;
-        int r;
-
-        assert(m);
-
-        if (m->llmnr_ipv4_udp_fd >= 0)
-                return m->llmnr_ipv4_udp_fd;
-
-        m->llmnr_ipv4_udp_fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
-        if (m->llmnr_ipv4_udp_fd < 0)
-                return -errno;
-
-        /* RFC 4795, section 2.5 recommends setting the TTL of UDP packets to 255. */
-        r = setsockopt(m->llmnr_ipv4_udp_fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
-        if (r < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        r = setsockopt(m->llmnr_ipv4_udp_fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl));
-        if (r < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        r = setsockopt(m->llmnr_ipv4_udp_fd, IPPROTO_IP, IP_MULTICAST_LOOP, &one, sizeof(one));
-        if (r < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        r = setsockopt(m->llmnr_ipv4_udp_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
-        if (r < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        r = setsockopt(m->llmnr_ipv4_udp_fd, IPPROTO_IP, IP_PKTINFO, &one, sizeof(one));
-        if (r < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        r = setsockopt(m->llmnr_ipv4_udp_fd, IPPROTO_IP, IP_RECVTTL, &one, sizeof(one));
-        if (r < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        /* Disable Don't-Fragment bit in the IP header */
-        r = setsockopt(m->llmnr_ipv4_udp_fd, IPPROTO_IP, IP_MTU_DISCOVER, &pmtu, sizeof(pmtu));
-        if (r < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        r = bind(m->llmnr_ipv4_udp_fd, &sa.sa, sizeof(sa.in));
-        if (r < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        r = sd_event_add_io(m->event, &m->llmnr_ipv4_udp_event_source, m->llmnr_ipv4_udp_fd, EPOLLIN, on_llmnr_packet, m);
-        if (r < 0)
-                goto fail;
-
-        return m->llmnr_ipv4_udp_fd;
-
-fail:
-        m->llmnr_ipv4_udp_fd = safe_close(m->llmnr_ipv4_udp_fd);
-        return r;
-}
-
-int manager_llmnr_ipv6_udp_fd(Manager *m) {
-        union sockaddr_union sa = {
-                .in6.sin6_family = AF_INET6,
-                .in6.sin6_port = htobe16(5355),
-        };
-        static const int one = 1, ttl = 255;
-        int r;
-
-        assert(m);
-
-        if (m->llmnr_ipv6_udp_fd >= 0)
-                return m->llmnr_ipv6_udp_fd;
-
-        m->llmnr_ipv6_udp_fd = socket(AF_INET6, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
-        if (m->llmnr_ipv6_udp_fd < 0)
-                return -errno;
-
-        r = setsockopt(m->llmnr_ipv6_udp_fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl));
-        if (r < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        /* RFC 4795, section 2.5 recommends setting the TTL of UDP packets to 255. */
-        r = setsockopt(m->llmnr_ipv6_udp_fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &ttl, sizeof(ttl));
-        if (r < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        r = setsockopt(m->llmnr_ipv6_udp_fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &one, sizeof(one));
-        if (r < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        r = setsockopt(m->llmnr_ipv6_udp_fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
-        if (r < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        r = setsockopt(m->llmnr_ipv6_udp_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
-        if (r < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        r = setsockopt(m->llmnr_ipv6_udp_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one));
-        if (r < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        r = setsockopt(m->llmnr_ipv6_udp_fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &one, sizeof(one));
-        if (r < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        r = bind(m->llmnr_ipv6_udp_fd, &sa.sa, sizeof(sa.in6));
-        if (r < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        r = sd_event_add_io(m->event, &m->llmnr_ipv6_udp_event_source, m->llmnr_ipv6_udp_fd, EPOLLIN, on_llmnr_packet, m);
-        if (r < 0)  {
-                r = -errno;
-                goto fail;
-        }
-
-        return m->llmnr_ipv6_udp_fd;
-
-fail:
-        m->llmnr_ipv6_udp_fd = safe_close(m->llmnr_ipv6_udp_fd);
-        return r;
-}
-
-static int on_llmnr_stream_packet(DnsStream *s) {
-        DnsScope *scope;
-
-        assert(s);
-
-        scope = manager_find_scope(s->manager, s->read_packet);
-        if (!scope) {
-                log_warning("Got LLMNR TCP packet on unknown scope. Ignroing.");
-                return 0;
-        }
-
-        if (dns_packet_validate_query(s->read_packet) > 0) {
-                log_debug("Got query packet for id %u", DNS_PACKET_ID(s->read_packet));
-
-                dns_scope_process_query(scope, s, s->read_packet);
-
-                /* If no reply packet was set, we free the stream */
-                if (s->write_packet)
-                        return 0;
-        } else
-                log_debug("Invalid LLMNR TCP packet.");
-
-        dns_stream_free(s);
-        return 0;
-}
-
-static int on_llmnr_stream(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
-        DnsStream *stream;
-        Manager *m = userdata;
-        int cfd, r;
-
-        cfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
-        if (cfd < 0) {
-                if (errno == EAGAIN || errno == EINTR)
-                        return 0;
-
-                return -errno;
-        }
-
-        r = dns_stream_new(m, &stream, DNS_PROTOCOL_LLMNR, cfd);
-        if (r < 0) {
-                safe_close(cfd);
-                return r;
-        }
-
-        stream->on_packet = on_llmnr_stream_packet;
-        return 0;
-}
-
-int manager_llmnr_ipv4_tcp_fd(Manager *m) {
-        union sockaddr_union sa = {
-                .in.sin_family = AF_INET,
-                .in.sin_port = htobe16(5355),
-        };
-        static const int one = 1, pmtu = IP_PMTUDISC_DONT;
-        int r;
-
-        assert(m);
-
-        if (m->llmnr_ipv4_tcp_fd >= 0)
-                return m->llmnr_ipv4_tcp_fd;
-
-        m->llmnr_ipv4_tcp_fd = socket(AF_INET, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
-        if (m->llmnr_ipv4_tcp_fd < 0)
-                return -errno;
-
-        /* RFC 4795, section 2.5. requires setting the TTL of TCP streams to 1 */
-        r = setsockopt(m->llmnr_ipv4_tcp_fd, IPPROTO_IP, IP_TTL, &one, sizeof(one));
-        if (r < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        r = setsockopt(m->llmnr_ipv4_tcp_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
-        if (r < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        r = setsockopt(m->llmnr_ipv4_tcp_fd, IPPROTO_IP, IP_PKTINFO, &one, sizeof(one));
-        if (r < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        r = setsockopt(m->llmnr_ipv4_tcp_fd, IPPROTO_IP, IP_RECVTTL, &one, sizeof(one));
-        if (r < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        /* Disable Don't-Fragment bit in the IP header */
-        r = setsockopt(m->llmnr_ipv4_tcp_fd, IPPROTO_IP, IP_MTU_DISCOVER, &pmtu, sizeof(pmtu));
-        if (r < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        r = bind(m->llmnr_ipv4_tcp_fd, &sa.sa, sizeof(sa.in));
-        if (r < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        r = listen(m->llmnr_ipv4_tcp_fd, SOMAXCONN);
-        if (r < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        r = sd_event_add_io(m->event, &m->llmnr_ipv4_tcp_event_source, m->llmnr_ipv4_tcp_fd, EPOLLIN, on_llmnr_stream, m);
-        if (r < 0)
-                goto fail;
-
-        return m->llmnr_ipv4_tcp_fd;
-
-fail:
-        m->llmnr_ipv4_tcp_fd = safe_close(m->llmnr_ipv4_tcp_fd);
-        return r;
-}
-
-int manager_llmnr_ipv6_tcp_fd(Manager *m) {
-        union sockaddr_union sa = {
-                .in6.sin6_family = AF_INET6,
-                .in6.sin6_port = htobe16(5355),
-        };
-        static const int one = 1;
-        int r;
-
-        assert(m);
-
-        if (m->llmnr_ipv6_tcp_fd >= 0)
-                return m->llmnr_ipv6_tcp_fd;
-
-        m->llmnr_ipv6_tcp_fd = socket(AF_INET6, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
-        if (m->llmnr_ipv6_tcp_fd < 0)
-                return -errno;
-
-        /* RFC 4795, section 2.5. requires setting the TTL of TCP streams to 1 */
-        r = setsockopt(m->llmnr_ipv6_tcp_fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &one, sizeof(one));
-        if (r < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        r = setsockopt(m->llmnr_ipv6_tcp_fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
-        if (r < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        r = setsockopt(m->llmnr_ipv6_tcp_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
-        if (r < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        r = setsockopt(m->llmnr_ipv6_tcp_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one));
-        if (r < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        r = setsockopt(m->llmnr_ipv6_tcp_fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &one, sizeof(one));
-        if (r < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        r = bind(m->llmnr_ipv6_tcp_fd, &sa.sa, sizeof(sa.in6));
-        if (r < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        r = listen(m->llmnr_ipv6_tcp_fd, SOMAXCONN);
-        if (r < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        r = sd_event_add_io(m->event, &m->llmnr_ipv6_tcp_event_source, m->llmnr_ipv6_tcp_fd, EPOLLIN, on_llmnr_stream, m);
-        if (r < 0)  {
-                r = -errno;
-                goto fail;
-        }
-
-        return m->llmnr_ipv6_tcp_fd;
-
-fail:
-        m->llmnr_ipv6_tcp_fd = safe_close(m->llmnr_ipv6_tcp_fd);
-        return r;
-}
-
 int manager_find_ifindex(Manager *m, int family, const union in_addr_union *in_addr) {
         LinkAddress *a;
 
diff --git a/src/resolve/resolved-manager.h b/src/resolve/resolved-manager.h
index 0f4ffad..4e70a5b 100644
--- a/src/resolve/resolved-manager.h
+++ b/src/resolve/resolved-manager.h
@@ -130,10 +130,6 @@ int manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret);
 
 int manager_dns_ipv4_fd(Manager *m);
 int manager_dns_ipv6_fd(Manager *m);
-int manager_llmnr_ipv4_udp_fd(Manager *m);
-int manager_llmnr_ipv6_udp_fd(Manager *m);
-int manager_llmnr_ipv4_tcp_fd(Manager *m);
-int manager_llmnr_ipv6_tcp_fd(Manager *m);
 
 int manager_find_ifindex(Manager *m, int family, const union in_addr_union *in_addr);
 LinkAddress* manager_find_link_address(Manager *m, int family, const union in_addr_union *in_addr);

commit f7c735017e97652f8ed76af2298bea23a80ac762
Merge: e43a839 d77c25b
Author: Daniel Mack <github at zonque.org>
Date:   Mon Jul 13 10:46:26 2015 -0400

    Merge pull request #573 from cmacq2/html-man-fixes
    
    Reproducible ID/name values for auto generated anchors in HTML output


commit d77c25b1164f55fe3f9b5ad00c47c0e01243ad53
Author: Johan Ouwerkerk <jm.ouwerkerk at gmail.com>
Date:   Mon Jul 13 10:39:09 2015 +0200

    doc: configure docbook stylesheet to generate reproducible IDs
    
    This makes auto generated anchor tags in HTML output reproducible.

diff --git a/man/custom-html.xsl b/man/custom-html.xsl
index f51fda7..1512763 100644
--- a/man/custom-html.xsl
+++ b/man/custom-html.xsl
@@ -22,6 +22,16 @@
 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
 
 <xsl:import href="http://docbook.sourceforge.net/release/xsl/current/html/docbook.xsl"/>
+<!--
+  - The docbook stylesheet injects empty anchor tags into generated HTML, identified by an auto-generated ID.
+  - Ask the docbook stylesheet to generate reproducible output when generating (these) ID values.
+  - This makes the output of this stylesheet reproducible across identical invocations on the same input,
+  - which is an easy and significant win for achieving reproducible builds.
+  -
+  - It may be even better to strip the empty anchors from the document output in addition to turning on consistent IDs,
+  - for this stylesheet contains its own custom ID logic (for generating permalinks) already.
+ -->
+<xsl:param name="generate.consistent.ids" select="1"/>
 
 <!-- translate man page references to links to html pages -->
 <xsl:template match="citerefentry[not(@project)]">

commit e43a8393eaf058c4ecd2a5968f59d83b911d4f1f
Author: Beniamino Galvani <bgalvani at redhat.com>
Date:   Thu Jul 9 18:04:01 2015 +0200

    dhcp: add support for vendor specific DHCP option
    
    This adds support for option 43 (Vendor Specific Information) to
    libsystemd-network DHCP code. The option carries an opaque object of n
    octets, interpreted by vendor-specific code on the clients and
    servers.
    
    [@zonque: adopted to new unhexmem() API]

diff --git a/src/libsystemd-network/dhcp-lease-internal.h b/src/libsystemd-network/dhcp-lease-internal.h
index 9e184ac..6e00b1a 100644
--- a/src/libsystemd-network/dhcp-lease-internal.h
+++ b/src/libsystemd-network/dhcp-lease-internal.h
@@ -72,6 +72,8 @@ struct sd_dhcp_lease {
         char *root_path;
         uint8_t *client_id;
         size_t client_id_len;
+        uint8_t *vendor_specific;
+        size_t vendor_specific_len;
 };
 
 int dhcp_lease_new(sd_dhcp_lease **ret);
diff --git a/src/libsystemd-network/dhcp-protocol.h b/src/libsystemd-network/dhcp-protocol.h
index abca942..aa37e9b 100644
--- a/src/libsystemd-network/dhcp-protocol.h
+++ b/src/libsystemd-network/dhcp-protocol.h
@@ -125,6 +125,7 @@ enum {
         DHCP_OPTION_BROADCAST                   = 28,
         DHCP_OPTION_STATIC_ROUTE                = 33,
         DHCP_OPTION_NTP_SERVER                  = 42,
+        DHCP_OPTION_VENDOR_SPECIFIC             = 43,
         DHCP_OPTION_REQUESTED_IP_ADDRESS        = 50,
         DHCP_OPTION_IP_ADDRESS_LEASE_TIME       = 51,
         DHCP_OPTION_OVERLOAD                    = 52,
diff --git a/src/libsystemd-network/sd-dhcp-lease.c b/src/libsystemd-network/sd-dhcp-lease.c
index 7548e50..e9bf3c9 100644
--- a/src/libsystemd-network/sd-dhcp-lease.c
+++ b/src/libsystemd-network/sd-dhcp-lease.c
@@ -179,6 +179,21 @@ int sd_dhcp_lease_get_routes(sd_dhcp_lease *lease, struct sd_dhcp_route **routes
         return 0;
 }
 
+int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease *lease, const uint8_t **data,
+                                      size_t *data_len) {
+        assert_return(lease, -EINVAL);
+        assert_return(data, -EINVAL);
+        assert_return(data_len, -EINVAL);
+
+        if (!lease->vendor_specific)
+                return -ENOENT;
+
+        *data = lease->vendor_specific;
+        *data_len = lease->vendor_specific_len;
+
+        return 0;
+}
+
 sd_dhcp_lease *sd_dhcp_lease_ref(sd_dhcp_lease *lease) {
         if (lease)
                 assert_se(REFCNT_INC(lease->n_ref) >= 2);
@@ -194,6 +209,7 @@ sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease) {
                 free(lease->ntp);
                 free(lease->static_route);
                 free(lease->client_id);
+                free(lease->vendor_specific);
                 free(lease);
         }
 
@@ -579,6 +595,17 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option,
                         return r;
 
                 break;
+
+        case DHCP_OPTION_VENDOR_SPECIFIC:
+                if (len >= 1) {
+                        free(lease->vendor_specific);
+                        lease->vendor_specific = memdup(option, len);
+                        if (!lease->vendor_specific)
+                                return -ENOMEM;
+                        lease->vendor_specific_len = len;
+                }
+
+               break;
         }
 
         return 0;
@@ -603,8 +630,8 @@ int sd_dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
         _cleanup_fclose_ FILE *f = NULL;
         struct in_addr address;
         const struct in_addr *addresses;
-        const uint8_t *client_id;
-        size_t client_id_len;
+        const uint8_t *client_id, *data;
+        size_t client_id_len, data_len;
         const char *string;
         uint16_t mtu;
         struct sd_dhcp_route *routes;
@@ -690,6 +717,18 @@ int sd_dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
                 fprintf(f, "CLIENTID=%s\n", client_id_hex);
         }
 
+        r = sd_dhcp_lease_get_vendor_specific(lease, &data, &data_len);
+        if (r >= 0) {
+                _cleanup_free_ char *option_hex = NULL;
+
+                option_hex = hexmem(data, data_len);
+                if (!option_hex) {
+                        r = -ENOMEM;
+                        goto finish;
+                }
+                fprintf(f, "VENDOR_SPECIFIC=%s\n", option_hex);
+        }
+
         r = 0;
 
         fflush(f);
@@ -712,7 +751,8 @@ int sd_dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
         _cleanup_free_ char *address = NULL, *router = NULL, *netmask = NULL,
                             *server_address = NULL, *next_server = NULL,
                             *dns = NULL, *ntp = NULL, *mtu = NULL,
-                            *routes = NULL, *client_id_hex = NULL;
+                            *routes = NULL, *client_id_hex = NULL,
+                            *vendor_specific_hex = NULL;
         struct in_addr addr;
         int r;
 
@@ -737,6 +777,7 @@ int sd_dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
                            "ROOT_PATH", &lease->root_path,
                            "ROUTES", &routes,
                            "CLIENTID", &client_id_hex,
+                           "VENDOR_SPECIFIC", &vendor_specific_hex,
                            NULL);
         if (r < 0) {
                 if (r == -ENOENT)
@@ -819,6 +860,15 @@ int sd_dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
                         return r;
         }
 
+        if (vendor_specific_hex) {
+                if (strlen(vendor_specific_hex) % 2)
+                        return -EINVAL;
+
+                r = unhexmem(vendor_specific_hex, strlen(vendor_specific_hex), (void**) &lease->vendor_specific, &lease->vendor_specific_len);
+                if (r < 0)
+                        return r;
+        }
+
         *ret = lease;
         lease = NULL;
 
diff --git a/src/systemd/sd-dhcp-lease.h b/src/systemd/sd-dhcp-lease.h
index 4296b91..5afa50a 100644
--- a/src/systemd/sd-dhcp-lease.h
+++ b/src/systemd/sd-dhcp-lease.h
@@ -45,6 +45,8 @@ int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname);
 int sd_dhcp_lease_get_hostname(sd_dhcp_lease *lease, const char **hostname);
 int sd_dhcp_lease_get_root_path(sd_dhcp_lease *lease, const char **root_path);
 int sd_dhcp_lease_get_routes(sd_dhcp_lease *lease, struct sd_dhcp_route **routesgn);
+int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease *lease, const uint8_t **data,
+                                      size_t *data_len);
 int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const uint8_t **client_id,
                                 size_t *client_id_len);
 

commit 89a2faeed5abf9ee284c157c1940a5ac1d829f9b
Merge: 9e40013 13a5d76
Author: Daniel Mack <github at zonque.org>
Date:   Sun Jul 12 14:10:39 2015 -0400

    Merge pull request #566 from teg/util-base64-2
    
    util: add base64 handling


commit 13a5d76b3277a2a499345cc24facc21eb17ccdae
Author: Tom Gundersen <teg at jklm.no>
Date:   Fri Jul 10 14:38:19 2015 +0200

    basic: util - add base64mem() function similar to hexmem()
    
    This implements RFC4648 for a slightly more compact representation of
    binary data compared to hex (6 bits per character rather than 4).

diff --git a/src/basic/util.c b/src/basic/util.c
index 61dd6c4..bc917ae 100644
--- a/src/basic/util.c
+++ b/src/basic/util.c
@@ -954,6 +954,180 @@ int unhexmem(const char *p, size_t l, void **mem, size_t *len) {
         return 0;
 }
 
+/* https://tools.ietf.org/html/rfc4648#section-4 */
+char base64char(int x) {
+        static const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+                                      "abcdefghijklmnopqrstuvwxyz"
+                                      "0123456789+/";
+        return table[x & 63];
+}
+
+int unbase64char(char c) {
+        unsigned offset;
+
+        if (c >= 'A' && c <= 'Z')
+                return c - 'A';
+
+        offset = 'Z' - 'A' + 1;
+
+        if (c >= 'a' && c <= 'z')
+                return c - 'a' + offset;
+
+        offset += 'z' - 'a' + 1;
+
+        if (c >= '0' && c <= '9')
+                return c - '0' + offset;
+
+        offset += '9' - '0' + 1;
+
+        if (c == '+')
+                return offset;
+
+        offset ++;
+
+        if (c == '/')
+                return offset;
+
+        return -EINVAL;
+}
+
+char *base64mem(const void *p, size_t l) {
+        char *r, *z;
+        const uint8_t *x;
+
+        /* three input bytes makes four output bytes, padding is added so we must round up */
+        z = r = malloc(4 * (l + 2) / 3 + 1);
+        if (!r)
+                return NULL;
+
+        for (x = p; x < (const uint8_t*) p + (l / 3) * 3; x += 3) {
+                /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ */
+                *(z++) = base64char(x[0] >> 2);                    /* 00XXXXXX */
+                *(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4);  /* 00XXYYYY */
+                *(z++) = base64char((x[1] & 15) << 2 | x[2] >> 6); /* 00YYYYZZ */
+                *(z++) = base64char(x[2] & 63);                    /* 00ZZZZZZ */
+        }
+
+        switch (l % 3) {
+        case 2:
+                *(z++) = base64char(x[0] >> 2);                   /* 00XXXXXX */
+                *(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4); /* 00XXYYYY */
+                *(z++) = base64char((x[1] & 15) << 2);            /* 00YYYY00 */
+                *(z++) = '=';
+
+                break;
+        case 1:
+                *(z++) = base64char(x[0] >> 2);        /* 00XXXXXX */
+                *(z++) = base64char((x[0] & 3) << 4);  /* 00XX0000 */
+                *(z++) = '=';
+                *(z++) = '=';
+
+                break;
+        }
+
+        *z = 0;
+        return r;
+}
+
+int unbase64mem(const char *p, size_t l, void **mem, size_t *_len) {
+        _cleanup_free_ uint8_t *t = NULL;
+        int a, b, c, d;
+        uint8_t *r, *z;
+        const char *x;
+        size_t len;
+
+        assert(p);
+
+        /* padding ensures any base63 input has input divisible by 4 */
+        if (l % 4 != 0)
+                return -EINVAL;
+
+        /* strip the padding */
+        if (l > 0 && p[l - 1] == '=')
+                l --;
+        if (l > 0 && p[l - 1] == '=')
+                l --;
+
+        /* a group of four input bytes needs three output bytes, in case of
+           padding we need to add two or three extra bytes */
+        len = (l / 4) * 3 + (l % 4 ? (l % 4) - 1 : 0);
+
+        z = r = malloc(len + 1);
+        if (!r)
+                return -ENOMEM;
+
+        for (x = p; x < p + (l / 4) * 4; x += 4) {
+                /* a == 00XXXXXX; b == 00YYYYYY; c == 00ZZZZZZ; d == 00WWWWWW */
+                a = unbase64char(x[0]);
+                if (a < 0)
+                        return -EINVAL;
+
+                b = unbase64char(x[1]);
+                if (b < 0)
+                        return -EINVAL;
+
+                c = unbase64char(x[2]);
+                if (c < 0)
+                        return -EINVAL;
+
+                d = unbase64char(x[3]);
+                if (d < 0)
+                        return -EINVAL;
+
+                *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
+                *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
+                *(z++) = (uint8_t) c << 6 | (uint8_t) d;      /* ZZWWWWWW */
+        }
+
+        switch (l % 4) {
+        case 3:
+                a = unbase64char(x[0]);
+                if (a < 0)
+                        return -EINVAL;
+
+                b = unbase64char(x[1]);
+                if (b < 0)
+                        return -EINVAL;
+
+                c = unbase64char(x[2]);
+                if (c < 0)
+                        return -EINVAL;
+
+                /* c == 00ZZZZ00 */
+                if (c & 3)
+                        return -EINVAL;
+
+                *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
+                *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
+
+                break;
+        case 2:
+                a = unbase64char(x[0]);
+                if (a < 0)
+                        return -EINVAL;
+
+                b = unbase64char(x[1]);
+                if (b < 0)
+                        return -EINVAL;
+
+                /* b == 00YY0000 */
+                if (b & 15)
+                        return -EINVAL;
+
+                *(z++) = (uint8_t) a << 2 | (uint8_t) (b >> 4); /* XXXXXXYY */
+
+                break;
+        }
+
+        *z = 0;
+
+        *mem = r;
+        r = NULL;
+        *_len = len;
+
+        return 0;
+}
+
 char octchar(int x) {
         return '0' + (x & 7);
 }
diff --git a/src/basic/util.h b/src/basic/util.h
index ea77907..dae4300 100644
--- a/src/basic/util.h
+++ b/src/basic/util.h
@@ -240,6 +240,8 @@ char octchar(int x) _const_;
 int unoctchar(char c) _const_;
 char decchar(int x) _const_;
 int undecchar(char c) _const_;
+char base64char(int x) _const_;
+int unbase64char(char c) _const_;
 
 char *cescape(const char *s);
 size_t cescape_char(char c, char *buf);
@@ -616,6 +618,9 @@ static inline void *mempset(void *s, int c, size_t n) {
 char *hexmem(const void *p, size_t l);
 int unhexmem(const char *p, size_t l, void **mem, size_t *len);
 
+char *base64mem(const void *p, size_t l);
+int unbase64mem(const char *p, size_t l, void **mem, size_t *len);
+
 char *strextend(char **x, ...) _sentinel_;
 char *strrep(const char *s, unsigned n);
 
diff --git a/src/test/test-util.c b/src/test/test-util.c
index f7949eb..72fbc34 100644
--- a/src/test/test-util.c
+++ b/src/test/test-util.c
@@ -390,6 +390,24 @@ static void test_unhexchar(void) {
         assert_se(unhexchar('0') == 0x0);
 }
 
+static void test_base64char(void) {
+        assert_se(base64char(0) == 'A');
+        assert_se(base64char(26) == 'a');
+        assert_se(base64char(63) == '/');
+}
+
+static void test_unbase64char(void) {
+        assert_se(unbase64char('A') == 0);
+        assert_se(unbase64char('Z') == 25);
+        assert_se(unbase64char('a') == 26);
+        assert_se(unbase64char('z') == 51);
+        assert_se(unbase64char('0') == 52);
+        assert_se(unbase64char('9') == 61);
+        assert_se(unbase64char('+') == 62);
+        assert_se(unbase64char('/') == 63);
+        assert_se(unbase64char('=') == -EINVAL);
+}
+
 static void test_octchar(void) {
         assert_se(octchar(00) == '0');
         assert_se(octchar(07) == '7');
@@ -434,6 +452,84 @@ static void test_unhexmem(void) {
         assert_se(memcmp(hex, hex2, strlen(hex) - 1) == 0);
 }
 
+/* https://tools.ietf.org/html/rfc4648#section-10 */
+static void test_base64mem(void) {
+        char *b64;
+
+        b64 = base64mem("", strlen(""));
+        assert_se(b64);
+        assert_se(streq(b64, ""));
+        free(b64);
+
+        b64 = base64mem("f", strlen("f"));
+        assert_se(b64);
+        assert_se(streq(b64, "Zg=="));
+        free(b64);
+
+        b64 = base64mem("fo", strlen("fo"));
+        assert_se(b64);
+        assert_se(streq(b64, "Zm8="));
+        free(b64);
+
+        b64 = base64mem("foo", strlen("foo"));
+        assert_se(b64);
+        assert_se(streq(b64, "Zm9v"));
+        free(b64);
+
+        b64 = base64mem("foob", strlen("foob"));
+        assert_se(b64);
+        assert_se(streq(b64, "Zm9vYg=="));
+        free(b64);
+
+        b64 = base64mem("fooba", strlen("fooba"));
+        assert_se(b64);
+        assert_se(streq(b64, "Zm9vYmE="));
+        free(b64);
+
+        b64 = base64mem("foobar", strlen("foobar"));
+        assert_se(b64);
+        assert_se(streq(b64, "Zm9vYmFy"));
+        free(b64);
+}
+
+static void test_unbase64mem(void) {
+        void *mem;
+        size_t len;
+
+        assert_se(unbase64mem("", strlen(""), &mem, &len) == 0);
+        assert_se(streq(strndupa(mem, len), ""));
+        free(mem);
+
+        assert_se(unbase64mem("Zg==", strlen("Zg=="), &mem, &len) == 0);
+        assert_se(streq(strndupa(mem, len), "f"));
+        free(mem);
+
+        assert_se(unbase64mem("Zm8=", strlen("Zm8="), &mem, &len) == 0);
+        assert_se(streq(strndupa(mem, len), "fo"));
+        free(mem);
+
+        assert_se(unbase64mem("Zm9v", strlen("Zm9v"), &mem, &len) == 0);
+        assert_se(streq(strndupa(mem, len), "foo"));
+        free(mem);
+
+        assert_se(unbase64mem("Zm9vYg==", strlen("Zm9vYg=="), &mem, &len) == 0);
+        assert_se(streq(strndupa(mem, len), "foob"));
+        free(mem);
+
+        assert_se(unbase64mem("Zm9vYmE=", strlen("Zm9vYmE="), &mem, &len) == 0);
+        assert_se(streq(strndupa(mem, len), "fooba"));
+        free(mem);
+
+        assert_se(unbase64mem("Zm9vYmFy", strlen("Zm9vYmFy"), &mem, &len) == 0);
+        assert_se(streq(strndupa(mem, len), "foobar"));
+        free(mem);
+
+        assert_se(unbase64mem("A", strlen("A"), &mem, &len) == -EINVAL);
+        assert_se(unbase64mem("A====", strlen("A===="), &mem, &len) == -EINVAL);
+        assert_se(unbase64mem("AAB==", strlen("AAB=="), &mem, &len) == -EINVAL);
+        assert_se(unbase64mem("AAAB=", strlen("AAAB="), &mem, &len) == -EINVAL);
+}
+
 static void test_cescape(void) {
         _cleanup_free_ char *escaped;
 
@@ -1828,11 +1924,15 @@ int main(int argc, char *argv[]) {
         test_in_charset();
         test_hexchar();
         test_unhexchar();
+        test_base64char();
+        test_unbase64char();
         test_octchar();
         test_unoctchar();
         test_decchar();
         test_undecchar();
         test_unhexmem();
+        test_base64mem();
+        test_unbase64mem();
         test_cescape();
         test_cunescape();
         test_foreach_word();

commit 30494563f235b21c6583f7476b8ee35e9f5f8048
Author: Tom Gundersen <teg at jklm.no>
Date:   Sat Jul 11 19:14:52 2015 +0200

    basic: util - fix errorhandling in unhexmem()
    
    We were ignoring failures from unhexchar, which meant that invalid
    hex characters were being turned into garbage rather than the string
    rejected.
    
    Fix this by making unhexmem return an error code, also change the API
    slightly, to return the size of the returned memory, reflecting the
    fact that the memory is a binary blob,and not a string.
    
    For convenience, still append a trailing NULL byte to the returned
    memory (not included in the returned size), allowing callers to
    treat it as a string without doing a second copy.

diff --git a/src/basic/util.c b/src/basic/util.c
index 13a67e9..61dd6c4 100644
--- a/src/basic/util.c
+++ b/src/basic/util.c
@@ -916,30 +916,42 @@ char *hexmem(const void *p, size_t l) {
         return r;
 }
 
-void *unhexmem(const char *p, size_t l) {
-        uint8_t *r, *z;
+int unhexmem(const char *p, size_t l, void **mem, size_t *len) {
+        _cleanup_free_ uint8_t *r = NULL;
+        uint8_t *z;
         const char *x;
 
+        assert(mem);
+        assert(len);
         assert(p);
 
         z = r = malloc((l + 1) / 2 + 1);
         if (!r)
-                return NULL;
+                return -ENOMEM;
 
         for (x = p; x < p + l; x += 2) {
                 int a, b;
 
                 a = unhexchar(x[0]);
-                if (x+1 < p + l)
+                if (a < 0)
+                        return a;
+                else if (x+1 < p + l) {
                         b = unhexchar(x[1]);
-                else
+                        if (b < 0)
+                                return b;
+                } else
                         b = 0;
 
                 *(z++) = (uint8_t) a << 4 | (uint8_t) b;
         }
 
         *z = 0;
-        return r;
+
+        *mem = r;
+        r = NULL;
+        *len = (l + 1) / 2;
+
+        return 0;
 }
 
 char octchar(int x) {
diff --git a/src/basic/util.h b/src/basic/util.h
index a1d1dd1..ea77907 100644
--- a/src/basic/util.h
+++ b/src/basic/util.h
@@ -614,7 +614,7 @@ static inline void *mempset(void *s, int c, size_t n) {
 }
 
 char *hexmem(const void *p, size_t l);
-void *unhexmem(const char *p, size_t l);
+int unhexmem(const char *p, size_t l, void **mem, size_t *len);
 
 char *strextend(char **x, ...) _sentinel_;
 char *strrep(const char *s, unsigned n);
diff --git a/src/libsystemd-network/sd-dhcp-lease.c b/src/libsystemd-network/sd-dhcp-lease.c
index d8bc76e..7548e50 100644
--- a/src/libsystemd-network/sd-dhcp-lease.c
+++ b/src/libsystemd-network/sd-dhcp-lease.c
@@ -811,13 +811,12 @@ int sd_dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
         }
 
         if (client_id_hex) {
-                if (strlen (client_id_hex) % 2)
+                if (strlen(client_id_hex) % 2)
                         return -EINVAL;
 
-                lease->client_id = unhexmem (client_id_hex, strlen (client_id_hex));
-                if (!lease->client_id)
-                        return -ENOMEM;
-                lease->client_id_len = strlen (client_id_hex) / 2;
+                r = unhexmem(client_id_hex, strlen(client_id_hex), (void**) &lease->client_id, &lease->client_id_len);
+                if (r < 0)
+                        return r;
         }
 
         *ret = lease;
diff --git a/src/libsystemd/sd-bus/bus-socket.c b/src/libsystemd/sd-bus/bus-socket.c
index 322d57d..735a775 100644
--- a/src/libsystemd/sd-bus/bus-socket.c
+++ b/src/libsystemd/sd-bus/bus-socket.c
@@ -264,6 +264,8 @@ static bool line_begins(const char *s, size_t m, const char *word) {
 
 static int verify_anonymous_token(sd_bus *b, const char *p, size_t l) {
         _cleanup_free_ char *token = NULL;
+        size_t len;
+        int r;
 
         if (!b->anonymous_auth)
                 return 0;
@@ -276,11 +278,12 @@ static int verify_anonymous_token(sd_bus *b, const char *p, size_t l) {
 
         if (l % 2 != 0)
                 return 0;
-        token = unhexmem(p, l);
-        if (!token)
-                return -ENOMEM;
 
-        if (memchr(token, 0, l/2))
+        r = unhexmem(p, l, (void **) &token, &len);
+        if (r < 0)
+                return 0;
+
+        if (memchr(token, 0, len))
                 return 0;
 
         return !!utf8_is_valid(token);
@@ -288,6 +291,7 @@ static int verify_anonymous_token(sd_bus *b, const char *p, size_t l) {
 
 static int verify_external_token(sd_bus *b, const char *p, size_t l) {
         _cleanup_free_ char *token = NULL;
+        size_t len;
         uid_t u;
         int r;
 
@@ -307,11 +311,11 @@ static int verify_external_token(sd_bus *b, const char *p, size_t l) {
         if (l % 2 != 0)
                 return 0;
 
-        token = unhexmem(p, l);
-        if (!token)
-                return -ENOMEM;
+        r = unhexmem(p, l, (void**) &token, &len);
+        if (r < 0)
+                return 0;
 
-        if (memchr(token, 0, l/2))
+        if (memchr(token, 0, len))
                 return 0;
 
         r = parse_uid(token, &u);
diff --git a/src/test/test-util.c b/src/test/test-util.c
index 9fbfece..f7949eb 100644
--- a/src/test/test-util.c
+++ b/src/test/test-util.c
@@ -410,6 +410,30 @@ static void test_undecchar(void) {
         assert_se(undecchar('9') == 9);
 }
 
+static void test_unhexmem(void) {
+        const char *hex = "efa214921";
+        const char *hex_invalid = "efa214921o";
+        _cleanup_free_ char *hex2 = NULL;
+        _cleanup_free_ void *mem = NULL;
+        size_t len;
+
+        assert_se(unhexmem(hex, strlen(hex), &mem, &len) == 0);
+        assert_se(unhexmem(hex, strlen(hex) + 1, &mem, &len) == -EINVAL);
+        assert_se(unhexmem(hex_invalid, strlen(hex_invalid), &mem, &len) == -EINVAL);
+
+        assert_se((hex2 = hexmem(mem, len)));
+
+        free(mem);
+
+        assert_se(memcmp(hex, hex2, strlen(hex)) == 0);
+
+        free(hex2);
+
+        assert_se(unhexmem(hex, strlen(hex) - 1, &mem, &len) == 0);
+        assert_se((hex2 = hexmem(mem, len)));
+        assert_se(memcmp(hex, hex2, strlen(hex) - 1) == 0);
+}
+
 static void test_cescape(void) {
         _cleanup_free_ char *escaped;
 
@@ -1808,6 +1832,7 @@ int main(int argc, char *argv[]) {
         test_unoctchar();
         test_decchar();
         test_undecchar();
+        test_unhexmem();
         test_cescape();
         test_cunescape();
         test_foreach_word();

commit 9e400131f799e7cb565bf2865b874d876cb2937f
Merge: 39fced0 aa11697
Author: Daniel Mack <github at zonque.org>
Date:   Sun Jul 12 11:33:27 2015 -0400

    Merge pull request #561 from cmacq2/html-man-fixes
    
    Html man fixes


commit 39fced01623e148d847010c6ee7fcfc552234018
Merge: 72c39d1 559b5cc
Author: Tom Gundersen <teg at jklm.no>
Date:   Sun Jul 12 11:44:45 2015 +0200

    Merge pull request #558 from poettering/logind-bus-policy
    
    logind: bring bus policy up-to-date


commit 72c39d1afef5ceaf308de3994bf5f99aac6a6eac
Merge: fdbbf0e b898f9b
Author: Tom Gundersen <teg at jklm.no>
Date:   Sun Jul 12 11:44:14 2015 +0200

    Merge pull request #556 from poettering/sd-bus-life-cycle
    
    man: go further into details regarding life-cycle of default bus conn…


commit fdbbf0eeda929451e2aaf34937a72f03a225e315
Merge: e239b62 2ed3de9
Author: Tom Gundersen <teg at jklm.no>
Date:   Sun Jul 12 11:43:51 2015 +0200

    Merge pull request #554 from poettering/ntp-pool
    
    build-sys: warn if people don't change the default NTP servers when b…


commit e239b628e095b68ad8f7e62c76c29dce9c6a940e
Merge: 08abe30 f4e74be
Author: Tom Gundersen <teg at jklm.no>
Date:   Sun Jul 12 11:43:10 2015 +0200

    Merge pull request #553 from poettering/rt-group-sched
    
    README: document that RT group sched should be turned off


commit aa1169774bbd61761965d826fe36bd071ec78656
Author: Johan Ouwerkerk <jm.ouwerkerk at gmail.com>
Date:   Sun Jul 12 03:07:24 2015 +0200

    Use a top-to-bottom numbering scheme for generating ids of subheadings and terms.
    This scheme fixes permalinks to distinguish between items that would previously have the same ID attribute.
    
    Where possible the generated ID values are the same as those generated with the previous versions of the stylesheet
    to retain backwards compatibility with published links.
    
    As a side effect of the changes xsltproc should no longer complain about duplicate IDs during build.

diff --git a/man/custom-html.xsl b/man/custom-html.xsl
index 2df1241..f51fda7 100644
--- a/man/custom-html.xsl
+++ b/man/custom-html.xsl
@@ -113,80 +113,122 @@
   </a>
 </xsl:template>
 
-<xsl:template match="refsect1/title|refsect1/info/title">
-  <!-- the ID is output in the block.object call for refsect1 -->
-  <h2>
+<!--
+  - helper template to do conflict resolution between various headings with the same inferred ID attribute/tag from the headerlink template
+  - this conflict resolution is necessary to prevent malformed HTML ouput (multiple id attributes with the same value)
+  - and it fixes xsltproc warnings during compilation of HTML man pages
+  -
+  - A simple top-to-bottom numbering scheme is implemented for nodes with the same ID value to derive unique ID values for HTML output.
+  - It uses two parameters:
+      templateID  the proposed ID string to use which must be checked for conflicts
+      keyNode     the context node which 'produced' the given templateID.
+  -
+  - Conflicts are detected solely based on keyNode, templateID is not taken into account for that purpose.
+ -->
+<xsl:template name="generateID">
+  <!-- node which generatedID needs to assume as the 'source' of the ID -->
+  <xsl:param name="keyNode"/>
+  <!-- suggested value for generatedID output, a contextually meaningful ID string -->
+  <xsl:param name="templateID"/>
+  <xsl:variable name="conflictSource" select="preceding::refsect1/title|preceding::refsect1/info/title|
+					      preceding::refsect2/title|preceding::refsect2/info/title|
+					      preceding::varlistentry/term[1]"/>
+  <xsl:variable name="conflictCount" select="count($conflictSource[. = $keyNode])"/>
+  <xsl:choose>
+    <!-- special case conflictCount = 0 to preserve compatibility with URLs generated by previous versions of this XSL stylesheet where possible -->
+    <xsl:when test="$conflictCount = 0">
+      <xsl:value-of select="$templateID"/>
+    </xsl:when>
+    <xsl:otherwise>
+      <xsl:value-of select="concat($templateID, $conflictCount)"/>
+    </xsl:otherwise>
+  </xsl:choose>
+</xsl:template>
+
+<!--
+  - a helper template to abstract over the structure of generated subheading + permalink HTML output
+  - It helps reduce tedious repetition and groups all actual markup output (as opposed to URL/ID logic) in a single location.
+ -->
+<xsl:template name="permalink">
+  <xsl:param name="nodeType"/> <!-- local name of the element node to generate, e.g. 'h2' for <h2></h2> -->
+  <xsl:param name="nodeContent"/> <!-- nodeset to apply further templates to obtain the content of the subheading/term -->
+  <xsl:param name="linkTitle"/> <!-- value for title attribute of generated permalink, e.g. 'this is a permalink' -->
+
+  <!-- parameters passed to generateID template, otherwise unused. -->
+  <xsl:param name="keyNode"/>
+  <xsl:param name="templateID"/>
+
+  <!--
+    - If stable URLs with fragment markers (references to the ID) turn out not to be important:
+    - generatedID could simply take the value of generate-id(), and various other helper templates may be dropped entirely.
+    - Alternatively if xsltproc is patched to generate reproducible generate-id() output the same simplifications can be
+    - applied at the cost of breaking compatibility with URLs generated from output of previous versions of this stylesheet.
+   -->
+  <xsl:variable name="generatedID">
+    <xsl:call-template name="generateID">
+      <xsl:with-param name="keyNode" select="$keyNode"/>
+      <xsl:with-param name="templateID" select="$templateID"/>
+    </xsl:call-template>
+  </xsl:variable>
+
+  <xsl:element name="{$nodeType}">
     <xsl:attribute name="id">
-      <xsl:call-template name="inline.charseq"/>
+      <xsl:value-of select="$generatedID"/>
     </xsl:attribute>
-    <xsl:apply-templates/>
-    <a>
-      <xsl:attribute name="class">
-        <xsl:text>headerlink</xsl:text>
-      </xsl:attribute>
-      <xsl:attribute name="title">
-        <xsl:text>Permalink to this headline</xsl:text>
-      </xsl:attribute>
-      <xsl:attribute name="href">
-        <xsl:text>#</xsl:text>
-        <xsl:call-template name="inline.charseq"/>
-      </xsl:attribute>
-      <xsl:text>¶</xsl:text>
-    </a>
-  </h2>
+    <xsl:apply-templates select="$nodeContent"/>
+    <a class="headerlink" title="{$linkTitle}" href="#{$generatedID}">¶</a>
+  </xsl:element>
 </xsl:template>
 
-<xsl:template match="refsect2/title|refsect2/info/title">
-  <h3>
-    <xsl:attribute name="id">
+<!-- simple wrapper around permalink to avoid repeating common info for each level of subheading covered by the permalink logic (h2, h3) -->
+<xsl:template name="headerlink">
+  <xsl:param name="nodeType"/>
+  <xsl:call-template name="permalink">
+    <xsl:with-param name="nodeType" select="$nodeType"/>
+    <xsl:with-param name="linkTitle" select="'Permalink to this headline'"/>
+    <xsl:with-param name="nodeContent" select="node()"/>
+    <xsl:with-param name="keyNode" select="."/>
+    <!--
+      - To retain compatibility with IDs generated by previous versions of the template, inline.charseq must be called.
+      - The purpose of that template is to generate markup (according to docbook documentation its purpose is to mark/format something as plain text).
+      - The only reason to call this template is to get the auto-generated text such as brackets ([]) before flattening it.
+     -->
+    <xsl:with-param name="templateID">
       <xsl:call-template name="inline.charseq"/>
-    </xsl:attribute>
-    <xsl:apply-templates/>
-    <a>
-      <xsl:attribute name="class">
-        <xsl:text>headerlink</xsl:text>
-      </xsl:attribute>
-      <xsl:attribute name="title">
-        <xsl:text>Permalink to this headline</xsl:text>
-      </xsl:attribute>
-      <xsl:attribute name="href">
-        <xsl:text>#</xsl:text>
-        <xsl:call-template name="inline.charseq"/>
-      </xsl:attribute>
-      <xsl:text>¶</xsl:text>
-    </a>
-  </h3>
+    </xsl:with-param>
+  </xsl:call-template>
+</xsl:template>
+
+<xsl:template match="refsect1/title|refsect1/info/title">
+  <!-- the ID is output in the block.object call for refsect1 -->
+  <xsl:call-template name="headerlink">
+    <xsl:with-param name="nodeType" select="'h2'"/>
+  </xsl:call-template>
+</xsl:template>
+
+<xsl:template match="refsect2/title|refsect2/info/title">
+  <xsl:call-template name="headerlink">
+    <xsl:with-param name="nodeType" select="'h3'"/>
+  </xsl:call-template>
 </xsl:template>
 
 <xsl:template match="varlistentry">
-  <dt>
-    <xsl:attribute name="id">
+  <xsl:call-template name="permalink">
+    <xsl:with-param name="nodeType" select="'dt'"/>
+    <xsl:with-param name="linkTitle" select="'Permalink to this term'"/>
+    <xsl:with-param name="nodeContent" select="term"/>
+    <xsl:with-param name="keyNode" select="term[1]"/>
+    <!--
+      - To retain compatibility with IDs generated by previous versions of the template, inline.charseq must be called.
+      - The purpose of that template is to generate markup (according to docbook documentation its purpose is to mark/format something as plain text).
+      - The only reason to call this template is to get the auto-generated text such as brackets ([]) before flattening it.
+     -->
+    <xsl:with-param name="templateID">
       <xsl:call-template name="inline.charseq">
-        <xsl:with-param name="content">
-          <xsl:copy-of select="term[position()=1]" />
-        </xsl:with-param>
+	<xsl:with-param name="content" select="term[1]"/>
       </xsl:call-template>
-    </xsl:attribute>
-    <xsl:apply-templates select="term"/>
-    <a>
-      <xsl:attribute name="class">
-        <xsl:text>headerlink</xsl:text>
-      </xsl:attribute>
-      <xsl:attribute name="title">
-        <xsl:text>Permalink to this term</xsl:text>
-      </xsl:attribute>
-      <xsl:attribute name="href">
-        <!--        <xsl:call-template name="href.target.uri" /> -->
-        <xsl:text>#</xsl:text>
-        <xsl:call-template name="inline.charseq">
-          <xsl:with-param name="content">
-            <xsl:copy-of select="term[position()=1]" />
-          </xsl:with-param>
-        </xsl:call-template>
-      </xsl:attribute>
-      <xsl:text>¶</xsl:text>
-    </a>
-  </dt>
+    </xsl:with-param>
+  </xsl:call-template>
   <dd>
     <xsl:apply-templates select="listitem"/>
   </dd>

commit a05185279bfc2420f60dc2a061d50bfcb646be70
Author: Nick Owens <mischief at coreos.com>
Date:   Thu Jul 9 12:51:55 2015 -0700

    sd-dhcp-lease: fix handling of multiple routers
    
    currently if a dhcp server sends more than one router, sd-dhcp-lease
    does not copy the ip because it assumes it will only ever be 4 bytes. a
    dhcp server could send more than one ip in the router list, so we should
    copy the first one and ignore the rest of the bytes.

diff --git a/src/libsystemd-network/sd-dhcp-lease.c b/src/libsystemd-network/sd-dhcp-lease.c
index d8bc76e..1150d04 100644
--- a/src/libsystemd-network/sd-dhcp-lease.c
+++ b/src/libsystemd-network/sd-dhcp-lease.c
@@ -435,7 +435,8 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option,
                 break;
 
         case DHCP_OPTION_ROUTER:
-                lease_parse_be32(option, len, &lease->router);
+                if(len >= 4)
+                        lease_parse_be32(option, 4, &lease->router);
 
                 break;
 

commit 08abe30e782549df5ca4199a816d67bff852e07b
Merge: 6f9d58d 6b62bbb
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sat Jul 11 19:32:58 2015 -0300

    Merge pull request #559 from poettering/logind-osindications-missing
    
    logind: some firmware implementations remove OsIndications if it is u…


commit 6b62bbbc7b53bee11778d27d18e9506d9b42d4ba
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sat Jul 11 17:29:48 2015 -0300

    logind: some firmware implementations remove OsIndications if it is unset
    
    We shouldn't fall over that, and just assume it is 0 in this case.
    
    Fixes #499.

diff --git a/src/shared/efivars.c b/src/shared/efivars.c
index 0d6ecf5..347cd30 100644
--- a/src/shared/efivars.c
+++ b/src/shared/efivars.c
@@ -125,7 +125,19 @@ static int get_os_indications(uint64_t *os_indication) {
                 return r;
 
         r = efi_get_variable(EFI_VENDOR_GLOBAL, "OsIndications", NULL, &v, &s);
-        if (r < 0)
+        if (r == -ENOENT) {
+                /* Some firmware implementations that do support
+                 * OsIndications and report that with
+                 * OsIndicationsSupported will remove the
+                 * OsIndications variable when it is unset. Let's
+                 * pretend it's 0 then, to hide this implementation
+                 * detail. Note that this call will return -ENOENT
+                 * then only if the support for OsIndications is
+                 * missing entirely, as determined by
+                 * efi_reboot_to_firmware_supported() above. */
+                *os_indication = 0;
+                return 0;
+        } else if (r < 0)
                 return r;
         else if (s != sizeof(uint64_t))
                 return -EINVAL;

commit 559b5cc2734bdd968c1c56ad1dc6fff08b8b30ba
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sat Jul 11 17:00:26 2015 -0300

    logind: bring bus policy up-to-date
    
    A while back we opened up all of logind's bus calls to unprivileged
    users, via PK. However, the dbus1 policy wasn't updated accordingly.
    
    With this change, the dbus1 policy is opened up for all bus calls that
    should be available to unprivileged clients.
    
    (also rearranges some calls in the vtable, to make more sense, and be in
    line with the order in the bus policy file)
    
    Fixes #471.

diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c
index ca435df..049e33e 100644
--- a/src/login/logind-dbus.c
+++ b/src/login/logind-dbus.c
@@ -2449,8 +2449,6 @@ const sd_bus_vtable manager_vtable[] = {
         SD_BUS_METHOD("PowerOff", "b", NULL, method_poweroff, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("Reboot", "b", NULL, method_reboot, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("Suspend", "b", NULL, method_suspend, SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD("ScheduleShutdown", "st", NULL, method_schedule_shutdown, SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD("CancelScheduledShutdown", NULL, "b", method_cancel_scheduled_shutdown, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("Hibernate", "b", NULL, method_hibernate, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("HybridSleep", "b", NULL, method_hybrid_sleep, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("CanPowerOff", NULL, "s", method_can_poweroff, SD_BUS_VTABLE_UNPRIVILEGED),
@@ -2458,6 +2456,8 @@ const sd_bus_vtable manager_vtable[] = {
         SD_BUS_METHOD("CanSuspend", NULL, "s", method_can_suspend, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("CanHibernate", NULL, "s", method_can_hibernate, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("CanHybridSleep", NULL, "s", method_can_hybrid_sleep, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("ScheduleShutdown", "st", NULL, method_schedule_shutdown, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("CancelScheduledShutdown", NULL, "b", method_cancel_scheduled_shutdown, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("Inhibit", "ssss", "h", method_inhibit, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("CanRebootToFirmwareSetup", NULL, "s", method_can_reboot_to_firmware_setup, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("SetRebootToFirmwareSetup", "b", NULL, method_set_reboot_to_firmware_setup, SD_BUS_VTABLE_UNPRIVILEGED),
diff --git a/src/login/org.freedesktop.login1.conf b/src/login/org.freedesktop.login1.conf
index 0ad7880..d8deb7b 100644
--- a/src/login/org.freedesktop.login1.conf
+++ b/src/login/org.freedesktop.login1.conf
@@ -90,6 +90,42 @@
 
                 <allow send_destination="org.freedesktop.login1"
                        send_interface="org.freedesktop.login1.Manager"
+                       send_member="LockSession"/>
+
+                <allow send_destination="org.freedesktop.login1"
+                       send_interface="org.freedesktop.login1.Manager"
+                       send_member="UnlockSession"/>
+
+                <allow send_destination="org.freedesktop.login1"
+                       send_interface="org.freedesktop.login1.Manager"
+                       send_member="LockSessions"/>
+
+                <allow send_destination="org.freedesktop.login1"
+                       send_interface="org.freedesktop.login1.Manager"
+                       send_member="UnlockSessions"/>
+
+                <allow send_destination="org.freedesktop.login1"
+                       send_interface="org.freedesktop.login1.Manager"
+                       send_member="KillSession"/>
+
+                <allow send_destination="org.freedesktop.login1"
+                       send_interface="org.freedesktop.login1.Manager"
+                       send_member="KillUser"/>
+
+                <allow send_destination="org.freedesktop.login1"
+                       send_interface="org.freedesktop.login1.Manager"
+                       send_member="TerminateSession"/>
+
+                <allow send_destination="org.freedesktop.login1"
+                       send_interface="org.freedesktop.login1.Manager"
+                       send_member="TerminateUser"/>
+
+                <allow send_destination="org.freedesktop.login1"
+                       send_interface="org.freedesktop.login1.Manager"
+                       send_member="TerminateSeat"/>
+
+                <allow send_destination="org.freedesktop.login1"
+                       send_interface="org.freedesktop.login1.Manager"
                        send_member="PowerOff"/>
 
                 <allow send_destination="org.freedesktop.login1"
@@ -130,6 +166,14 @@
 
                 <allow send_destination="org.freedesktop.login1"
                        send_interface="org.freedesktop.login1.Manager"
+                       send_member="ScheduleShutdown"/>
+
+                <allow send_destination="org.freedesktop.login1"
+                       send_interface="org.freedesktop.login1.Manager"
+                       send_member="CancelScheduledShutdown"/>
+
+                <allow send_destination="org.freedesktop.login1"
+                       send_interface="org.freedesktop.login1.Manager"
                        send_member="CanRebootToFirmwareSetup"/>
 
                 <allow send_destination="org.freedesktop.login1"
@@ -146,6 +190,10 @@
 
                 <allow send_destination="org.freedesktop.login1"
                        send_interface="org.freedesktop.login1.Seat"
+                       send_member="Terminate"/>
+
+                <allow send_destination="org.freedesktop.login1"
+                       send_interface="org.freedesktop.login1.Seat"
                        send_member="ActivateSession"/>
 
                 <allow send_destination="org.freedesktop.login1"
@@ -162,14 +210,30 @@
 
                 <allow send_destination="org.freedesktop.login1"
                        send_interface="org.freedesktop.login1.Session"
+                       send_member="Terminate"/>
+
+                <allow send_destination="org.freedesktop.login1"
+                       send_interface="org.freedesktop.login1.Session"
                        send_member="Activate"/>
 
                 <allow send_destination="org.freedesktop.login1"
                        send_interface="org.freedesktop.login1.Session"
+                       send_member="Lock"/>
+
+                <allow send_destination="org.freedesktop.login1"
+                       send_interface="org.freedesktop.login1.Session"
+                       send_member="Unlock"/>
+
+                <allow send_destination="org.freedesktop.login1"
+                       send_interface="org.freedesktop.login1.Session"
                        send_member="SetIdleHint"/>
 
                 <allow send_destination="org.freedesktop.login1"
                        send_interface="org.freedesktop.login1.Session"
+                       send_member="Kill"/>
+
+                <allow send_destination="org.freedesktop.login1"
+                       send_interface="org.freedesktop.login1.Session"
                        send_member="TakeControl"/>
 
                 <allow send_destination="org.freedesktop.login1"
@@ -188,6 +252,14 @@
                        send_interface="org.freedesktop.login1.Session"
                        send_member="PauseDeviceComplete"/>
 
+                <allow send_destination="org.freedesktop.login1"
+                       send_interface="org.freedesktop.login1.User"
+                       send_member="Terminate"/>
+
+                <allow send_destination="org.freedesktop.login1"
+                       send_interface="org.freedesktop.login1.User"
+                       send_member="Kill"/>
+
                 <allow receive_sender="org.freedesktop.login1"/>
         </policy>
 

commit b898f9bd7eb803521ee8e5d51fe2174967541f86
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sat Jul 11 16:11:45 2015 -0300

    man: go further into details regarding life-cycle of default bus connection objects
    
    This extends on PR #542.

diff --git a/man/sd_bus_default.xml b/man/sd_bus_default.xml
index 782dfb5..1cf2cb8 100644
--- a/man/sd_bus_default.xml
+++ b/man/sd_bus_default.xml
@@ -111,9 +111,9 @@
     <para><function>sd_bus_default()</function> acquires a bus
     connection object to the user bus when invoked in user context, or
     to the system bus otherwise. The connection object is associated
-    to the calling thread. Each time the function is invoked from the
-    same thread the same object is returned, but its reference count
-    is increased by one, as long as at least one reference is
+    with the calling thread. Each time the function is invoked from
+    the same thread the same object is returned, but its reference
+    count is increased by one, as long as at least one reference is
     kept. When the last reference to the connection is dropped (using
     the
     <citerefentry><refentrytitle>sd_bus_unref</refentrytitle><manvolnum>3</manvolnum></citerefentry>
@@ -121,10 +121,11 @@
     not automatically terminated when the associated thread ends. It
     is important to drop the last reference to the bus connection
     explicitly before the thread ends or otherwise the connection will
-    be leaked.</para>
+    be leaked. Also, queued but unread or unwritten messages keep the
+    bus referenced, see below.</para>
 
     <para><function>sd_bus_default_user()</function> returns a user
-    bus connection object associated to the calling thread.
+    bus connection object associated with the calling thread.
     <function>sd_bus_default_system()</function> is similar, but
     connects to the system bus. Note that
     <function>sd_bus_default()</function> is identical to these two
@@ -193,38 +194,63 @@
   </refsect1>
 
   <refsect1>
-    <title>Return Value</title>
-
-    <para>On success, these calls return 0 or a positive
-    integer. On failure, these calls return a negative
-    errno-style error code.</para>
-  </refsect1>
-
-  <refsect1>
     <title>Reference ownership</title>
     <para>The functions <function>sd_bus_open()</function>,
     <function>sd_bus_open_user()</function>,
     <function>sd_bus_open_system()</function>,
     <function>sd_bus_open_system_remote()</function>, and
     <function>sd_bus_open_system_machine()</function> return a new
-    object and the caller owns the sole reference. When not needed
-    anymore, this reference should be destroyed with
+    connection object and the caller owns the sole reference. When not
+    needed anymore, this reference should be destroyed with
     <citerefentry><refentrytitle>sd_bus_unref</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
     </para>
 
     <para>The functions <function>sd_bus_default()</function>,
     <function>sd_bus_default_user()</function> and
     <function>sd_bus_default_system()</function> do not necessarily
-    create a new object, but increase the connection reference by
-    one. Use
+    create a new object, but increase the connection reference of an
+    existing connection object by one. Use
     <citerefentry><refentrytitle>sd_bus_unref</refentrytitle><manvolnum>3</manvolnum></citerefentry>
     to drop the reference.</para>
 
-    <para>Queued messages also keep a reference to the bus. For this reason, just
-    because no application is having a reference to the bus does not mean that
-    the bus object will be destroyed. Until all the messages are sent, the bus object
-    will stay alive. <function>sd_bus_flush</function> can be used to send all the
-    queued messages so they drop their references.</para>
+    <para>Queued but unwritten/unread messages also keep a reference
+    to their bus connection object. For this reason, even if an
+    application dropped all references to a bus connection it might
+    not get destroyed right-away. Until all incoming queued
+    messages are read, and until all outgoing unwritten messages are
+    written, the bus object will stay
+    alive. <function>sd_bus_flush()</function> may be used to write
+    all outgoing queued messages so they drop their references. To
+    flush the unread incoming messages use
+    <function>sd_bus_close()</function>, which will also close the bus
+    connection. When using the default bus logic it is a good idea to
+    first invoke <function>sd_bus_flush()</function> followed by
+    <function>sd_bus_close()</function> when a thread or process
+    terminates, and thus its bus connection object should be
+    freed.</para>
+
+    <para>The life-cycle of the default bus connection should be the
+    responsibility of the code that creates/owns the thread the
+    default bus connection object is associated with. Library code
+    should neither call <function>sd_bus_flush()</function> nor
+    <function>sd_bus_close()</function> on default bus objects unless
+    it does so in its own private, self-allocated thread. Library code
+    should not use the default bus object in other threads unless it
+    is clear that the program using it will life-cycle the bus
+    connection object and flush and close it before exiting from the
+    thread. In libraries where it is not clear that the calling
+    program will life-cycle the bus connection object it is hence
+    recommended to use <function>sd_bus_open_system()</function>
+    instead of <function>sd_bus_default_system()</function> and
+    related calls.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>Return Value</title>
+
+    <para>On success, these calls return 0 or a positive
+    integer. On failure, these calls return a negative
+    errno-style error code.</para>
   </refsect1>
 
   <refsect1>

commit f4e74be1856b3ac058acbf1be321c31d5299f69f
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sat Jul 11 14:18:35 2015 -0300

    README: document that RT group sched should be turned off
    
    https://bugs.freedesktop.org/show_bug.cgi?id=87570
    https://bugzilla.redhat.com/show_bug.cgi?id=1229700

diff --git a/README b/README
index 53220ff..e15fa77 100644
--- a/README
+++ b/README
@@ -82,11 +82,11 @@ REQUIREMENTS:
           CONFIG_SECCOMP
           CONFIG_CHECKPOINT_RESTORE (for the kcmp() syscall)
 
-        Required for CPUShares in resource control unit settings
+        Required for CPUShares= in resource control unit settings
           CONFIG_CGROUP_SCHED
           CONFIG_FAIR_GROUP_SCHED
 
-        Required for CPUQuota in resource control unit settings
+        Required for CPUQuota= in resource control unit settings
           CONFIG_CFS_BANDWIDTH
 
         For systemd-bootchart, several proc debug interfaces are required:
@@ -97,6 +97,15 @@ REQUIREMENTS:
           CONFIG_EFIVAR_FS
           CONFIG_EFI_PARTITION
 
+        We recommend to turn off Real-Time group scheduling in the
+        kernel when using systemd. RT group scheduling effectively
+        makes RT scheduling unavailable for most userspace, since it
+        requires explicit assignment of RT budgets to each unit whose
+        processes making use of RT. As there's no sensible way to
+        assign these budgets automatically this cannot really be
+        fixed, and it's best to disable group scheduling hence.
+           CONFIG_RT_GROUP_SCHED=n
+
         Note that kernel auditing is broken when used with systemd's
         container code. When using systemd in conjunction with
         containers, please make sure to either turn off auditing at

commit 6f9d58d87fa2b728c1d08f74e9f17c581513516c
Merge: 0dc705b 64ee7ab
Author: Daniel Mack <github at zonque.org>
Date:   Sat Jul 11 13:35:50 2015 -0400

    Merge pull request #551 from poettering/fopen-temporary-noerrno
    
    util: make sure we don't clobber errno in error path


commit 0dc705bee2dddfa093b47e5459f2c6dac37033c0
Merge: 49aa7ab 10c03e9
Author: Daniel Mack <github at zonque.org>
Date:   Sat Jul 11 13:35:24 2015 -0400

    Merge pull request #552 from poettering/path-is-mount-point-simplification
    
    basic: simplify path_is_mount_point() a bit


commit 2ed3de9cc4f80670cd911536c3e40239fb0e2aa6
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sat Jul 11 14:16:40 2015 -0300

    build-sys: warn if people don't change the default NTP servers when building systemd
    
    Also, explain the situation in the docs.
    
    Relates to #437

diff --git a/DISTRO_PORTING b/DISTRO_PORTING
index d8e9ded..07aea86 100644
--- a/DISTRO_PORTING
+++ b/DISTRO_PORTING
@@ -14,6 +14,7 @@ HOWTO:
             --with-kbd-loadkeys=
             --with-kbd-setfont=
             --with-tty-gid=
+            --with-ntp-servers=
 
         2) Try it out. Play around (as an ordinary user) with
         '/usr/lib/systemd/systemd --test --system' for a test run
@@ -21,6 +22,24 @@ HOWTO:
         print the initial transaction it would execute during boot-up.
         This will also inform you about ordering loops and suchlike
 
+NTP POOL:
+
+        By default, timesyncd uses the Google NTP servers
+        time[1-4].google.com. They serve time that is not standards
+        compliant, and can be up to .5s off. Google does not
+        officially support these servers for the broader
+        audience. Distributions and vendors really should not ship
+        OSes or devices with these NTP servers configured. Instead,
+        please register your own vendor pool at ntp.org and make it
+        the built-in default by passing --with-ntp-servers= to
+        configure. Registering vendor pools is free:
+
+        http://www.pool.ntp.org/en/vendors.html
+
+        Again, if you ship your software or device with the default
+        NTP servers, then you will get served wrong time, and will
+        rely on services that might not be supported for long.
+
 CONTRIBUTING UPSTREAM:
 
         We generally do no longer accept distribution-specific
diff --git a/README b/README
index 53220ff..ba8d693 100644
--- a/README
+++ b/README
@@ -261,6 +261,11 @@ WARNINGS:
         false positives will be triggered by code which violates
         some rules but is actually safe.
 
+        Currently, systemd-timesyncd defaults to use the Google NTP
+        servers if not specified otherwise at configure time. You
+        really should not ship an OS or device with this default
+        setting. See DISTRO_PORTING for details.
+
 ENGINEERING AND CONSULTING SERVICES:
         ENDOCODE <https://endocode.com/> offers professional
         engineering and consulting services for systemd. Please
diff --git a/configure.ac b/configure.ac
index 6804e03..999f9f8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1009,7 +1009,8 @@ AC_ARG_WITH(ntp-servers,
         AS_HELP_STRING([--with-ntp-servers=NTPSERVERS],
                 [Space-separated list of default NTP servers]),
         [NTP_SERVERS="$withval"],
-        [NTP_SERVERS="time1.google.com time2.google.com time3.google.com time4.google.com"])
+        [NTP_SERVERS="time1.google.com time2.google.com time3.google.com time4.google.com"
+        AC_MSG_WARN([*** Using Google NTP servers. Please do not ship OSes or devices with these default settings. See DISTRO_PORTING for details!])])
 
 AC_DEFINE_UNQUOTED(NTP_SERVERS, ["$NTP_SERVERS"], [Default NTP Servers])
 AC_SUBST(NTP_SERVERS)

commit 10c03e9e82258fee9a9af4c4eacdc4af1e52680c
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sat Jul 11 14:20:38 2015 -0300

    basic: simplify path_is_mount_point() a bit
    
    This removes two uses of the ternary operator.

diff --git a/src/basic/path-util.c b/src/basic/path-util.c
index 8f49d65..5cbfc14 100644
--- a/src/basic/path-util.c
+++ b/src/basic/path-util.c
@@ -656,9 +656,11 @@ int path_is_mount_point(const char *t, int flags) {
                 canonical = canonicalize_file_name(t);
                 if (!canonical)
                         return -errno;
+
+                t = canonical;
         }
 
-        r = path_get_parent(canonical ?: t, &parent);
+        r = path_get_parent(t, &parent);
         if (r < 0)
                 return r;
 
@@ -666,7 +668,7 @@ int path_is_mount_point(const char *t, int flags) {
         if (fd < 0)
                 return -errno;
 
-        return fd_is_mount_point(fd, basename(canonical ?: t), flags);
+        return fd_is_mount_point(fd, basename(t), flags);
 }
 
 int path_is_read_only_fs(const char *path) {

commit 64ee7ab46211307cea338f35694c802f7abc313f
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sat Jul 11 14:19:36 2015 -0300

    util: make sure we don't clobber errno in error path

diff --git a/src/basic/util.c b/src/basic/util.c
index c88cd1d..13a67e9 100644
--- a/src/basic/util.c
+++ b/src/basic/util.c
@@ -2533,7 +2533,7 @@ int fopen_temporary(const char *path, FILE **_f, char **_temp_path) {
 
         f = fdopen(fd, "we");
         if (!f) {
-                unlink(t);
+                unlink_noerrno(t);
                 free(t);
                 safe_close(fd);
                 return -errno;

commit 49aa7ab6e1aa558ec96a49218993e25f1b82c703
Merge: f2db89c ac59f0c
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sat Jul 11 12:17:39 2015 -0300

    Merge pull request #535 from martinpitt/master
    
    units: emergency.service: wait for plymouth to shut down


commit f2db89c99cd9d4fd78581101ef8f74ee784a5818
Merge: 537c165 3541bf1
Author: Daniel Mack <github at zonque.org>
Date:   Fri Jul 10 20:42:32 2015 -0400

    Merge pull request #548 from vcaputo/fix_path_state_debug_msg
    
    core: include unit in path state transition debug logging.


commit 3541bf1f07cca5bdd14006f5ab42a915e8258b52
Author: Vito Caputo <vito.caputo at coreos.com>
Date:   Fri Jul 10 16:40:46 2015 -0700

    core: include unit in path state transition debug logging.

diff --git a/src/core/path.c b/src/core/path.c
index 6d26d89..20995d9 100644
--- a/src/core/path.c
+++ b/src/core/path.c
@@ -426,7 +426,7 @@ static void path_set_state(Path *p, PathState state) {
                 path_unwatch(p);
 
         if (state != old_state)
-                log_debug("Changed %s -> %s", path_state_to_string(old_state), path_state_to_string(state));
+                log_unit_debug(UNIT(p), "Changed %s -> %s", path_state_to_string(old_state), path_state_to_string(state));
 
         unit_notify(UNIT(p), state_translation_table[old_state], state_translation_table[state], true);
 }

commit 537c1656c89c137aa09a836f91f9e685c8fdb87d
Merge: e6494a0 db03761
Author: Daniel Mack <github at zonque.org>
Date:   Fri Jul 10 11:23:18 2015 -0400

    Merge pull request #542 from utezduyar/sd_unref-might-keep-bus-alive
    
    man: sd_unref does not necessarily free the bus


commit e6494a07cbbfa93dd83782fa1f8554aa4d2353bd
Author: David Herrmann <dh.herrmann at gmail.com>
Date:   Fri Jul 10 15:08:24 2015 +0200

    logind: rename 'pos' to 'position'
    
    Spell out the proper name. Use 'pos' over 'position', and also update the
    logind state file to do the same. Note that this breaks live updates.
    However, we only save 'POSITION' on non-seat0, so this shouldn't bother
    anyone for real. If you run multi-seat setups, you better restart a
    machine on updates, anyway.

diff --git a/src/login/logind-seat.c b/src/login/logind-seat.c
index fb5d076..9d5287a 100644
--- a/src/login/logind-seat.c
+++ b/src/login/logind-seat.c
@@ -290,8 +290,8 @@ int seat_switch_to_next(Seat *s) {
                 return -EINVAL;
 
         start = 1;
-        if (s->active && s->active->pos > 0)
-                start = s->active->pos;
+        if (s->active && s->active->position > 0)
+                start = s->active->position;
 
         for (i = start + 1; i < s->position_count; ++i)
                 if (s->positions[i])
@@ -311,8 +311,8 @@ int seat_switch_to_previous(Seat *s) {
                 return -EINVAL;
 
         start = 1;
-        if (s->active && s->active->pos > 0)
-                start = s->active->pos;
+        if (s->active && s->active->position > 0)
+                start = s->active->position;
 
         for (i = start - 1; i > 0; --i)
                 if (s->positions[i])
@@ -472,9 +472,9 @@ int seat_stop_sessions(Seat *s, bool force) {
 
 void seat_evict_position(Seat *s, Session *session) {
         Session *iter;
-        unsigned int pos = session->pos;
+        unsigned int pos = session->position;
 
-        session->pos = 0;
+        session->position = 0;
 
         if (pos == 0)
                 return;
@@ -486,7 +486,7 @@ void seat_evict_position(Seat *s, Session *session) {
                  * position (eg., during gdm->session transition), so let's look
                  * for it and set it on the free slot. */
                 LIST_FOREACH(sessions_by_seat, iter, s->sessions) {
-                        if (iter->pos == pos) {
+                        if (iter->position == pos) {
                                 s->positions[pos] = iter;
                                 break;
                         }
@@ -504,7 +504,7 @@ void seat_claim_position(Seat *s, Session *session, unsigned int pos) {
 
         seat_evict_position(s, session);
 
-        session->pos = pos;
+        session->position = pos;
         if (pos > 0 && !s->positions[pos])
                 s->positions[pos] = session;
 }
@@ -512,7 +512,7 @@ void seat_claim_position(Seat *s, Session *session, unsigned int pos) {
 static void seat_assign_position(Seat *s, Session *session) {
         unsigned int pos;
 
-        if (session->pos > 0)
+        if (session->position > 0)
                 return;
 
         for (pos = 1; pos < s->position_count; ++pos)
diff --git a/src/login/logind-session.c b/src/login/logind-session.c
index 6a450b0..45f4c09 100644
--- a/src/login/logind-session.c
+++ b/src/login/logind-session.c
@@ -264,7 +264,7 @@ int session_save(Session *s) {
                 fprintf(f, "VTNR=%u\n", s->vtnr);
 
         if (!s->vtnr)
-                fprintf(f, "POS=%u\n", s->pos);
+                fprintf(f, "POSITION=%u\n", s->position);
 
         if (s->leader > 0)
                 fprintf(f, "LEADER="PID_FMT"\n", s->leader);
@@ -302,7 +302,7 @@ int session_load(Session *s) {
                 *seat = NULL,
                 *vtnr = NULL,
                 *state = NULL,
-                *pos = NULL,
+                *position = NULL,
                 *leader = NULL,
                 *type = NULL,
                 *class = NULL,
@@ -329,7 +329,7 @@ int session_load(Session *s) {
                            "DESKTOP",        &s->desktop,
                            "VTNR",           &vtnr,
                            "STATE",          &state,
-                           "POS",            &pos,
+                           "POSITION",       &position,
                            "LEADER",         &leader,
                            "TYPE",           &type,
                            "CLASS",          &class,
@@ -388,10 +388,10 @@ int session_load(Session *s) {
         if (!s->seat || !seat_has_vts(s->seat))
                 s->vtnr = 0;
 
-        if (pos && s->seat) {
+        if (position && s->seat) {
                 unsigned int npos;
 
-                safe_atou(pos, &npos);
+                safe_atou(position, &npos);
                 seat_claim_position(s->seat, s, npos);
         }
 
diff --git a/src/login/logind-session.h b/src/login/logind-session.h
index 4bf739a..b8565eb 100644
--- a/src/login/logind-session.h
+++ b/src/login/logind-session.h
@@ -70,7 +70,7 @@ struct Session {
         Manager *manager;
 
         const char *id;
-        unsigned int pos;
+        unsigned int position;
         SessionType type;
         SessionClass class;
 

commit cc85d56245a21e458dbc955fbf94fa9b3bfb9e33
Author: David Herrmann <dh.herrmann at gmail.com>
Date:   Fri Jul 10 14:53:08 2015 +0200

    logind: allow greeters to take over VTs
    
    Make sure a greeter can forcefully spawn a session on a VT that is
    in-use. A recent patch prevented this (this used to be possible for all
    session types) as it is highly fragile. However, as it turns out,
    greeters seem to rely on that feature. Therefore, make sure we allow it
    explicitly for greeters.

diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c
index cd9cab7..ca435df 100644
--- a/src/login/logind-dbus.c
+++ b/src/login/logind-dbus.c
@@ -699,9 +699,12 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus
          * after the user-session and want the user-session to take
          * over the VT. We need to support this for
          * backwards-compatibility, so make sure we allow new sessions
-         * on a VT that a greeter is running on.
+         * on a VT that a greeter is running on. Furthermore, to allow
+         * re-logins, we have to allow a greeter to take over a used VT for
+         * the exact same reasons.
          */
-        if (vtnr > 0 &&
+        if (c != SESSION_GREETER &&
+            vtnr > 0 &&
             vtnr < m->seat0->position_count &&
             m->seat0->positions[vtnr] &&
             m->seat0->positions[vtnr]->class != SESSION_GREETER)

commit db03761e16f945fdc639f88a0c316eeda665980b
Author: Umut Tezduyar Lindskog <umuttl at axis.com>
Date:   Fri Jul 10 14:31:53 2015 +0200

    man: sd_unref does not necessarily free the bus
    
    Document that sd_unref() does not necessarily free the bus,
    even if no part of the program explicitly refs it, due to
    the queued messages.

diff --git a/man/sd_bus_default.xml b/man/sd_bus_default.xml
index 95b347b..782dfb5 100644
--- a/man/sd_bus_default.xml
+++ b/man/sd_bus_default.xml
@@ -219,6 +219,12 @@
     one. Use
     <citerefentry><refentrytitle>sd_bus_unref</refentrytitle><manvolnum>3</manvolnum></citerefentry>
     to drop the reference.</para>
+
+    <para>Queued messages also keep a reference to the bus. For this reason, just
+    because no application is having a reference to the bus does not mean that
+    the bus object will be destroyed. Until all the messages are sent, the bus object
+    will stay alive. <function>sd_bus_flush</function> can be used to send all the
+    queued messages so they drop their references.</para>
   </refsect1>
 
   <refsect1>
diff --git a/man/sd_bus_new.xml b/man/sd_bus_new.xml
index 44744a0..aff2ed2 100644
--- a/man/sd_bus_new.xml
+++ b/man/sd_bus_new.xml
@@ -77,8 +77,8 @@
     <para><function>sd_bus_new()</function> creates a new bus
     object. This object is reference-counted, and will be destroyed
     when all references are gone. Initially, the caller of this
-    function owns the sole reference. The bus object will not be
-    connected to any bus initially. To connect it to a bus, make sure
+    function owns the sole reference and the bus object will not be
+    connected to any bus. To connect it to a bus, make sure
     to set an address with
     <citerefentry><refentrytitle>sd_bus_set_address</refentrytitle><manvolnum>3</manvolnum></citerefentry>
     or a related call, and then start the connection with
@@ -94,15 +94,13 @@
     well-known bus in a single function invocation.</para>
 
     <para><function>sd_bus_ref()</function> creates a new reference to
-    <parameter>bus</parameter>. This bus object will not be destroyed
-    until <function>sd_bus_unref()</function> has been called as many
-    times plus once more. Once the reference count has dropped to
-    zero, <parameter>bus</parameter> cannot be used anymore, so
-    further calls to <function>sd_bus_ref()</function> or
-    <function>sd_bus_unref()</function> are illegal.</para>
+    <parameter>bus</parameter>.</para>
 
     <para><function>sd_bus_unref()</function> destroys a reference to
-    <parameter>bus</parameter>.</para>
+    <parameter>bus</parameter>. Once the reference count has dropped
+    to zero, <parameter>bus</parameter> cannot be used anymore, so
+    further calls to <function>sd_bus_ref()</function> or
+    <function>sd_bus_unref()</function> are illegal.</para>
   </refsect1>
 
   <refsect1>

commit ac59f0c12c117b9bb5b7e17f33987b0107791239
Author: Martin Pitt <martin.pitt at ubuntu.com>
Date:   Thu Jul 9 16:25:00 2015 +0200

    units: emergency.service: wait for plymouth to shut down
    
    Merely calling "plymouth quit" isn't sufficient, as plymouth needs some time to
    shut down. This needs plymouth --wait (which is a no-op when it's not running).
    
    Fixes invisible emergency shell with plymouth running endlessly.
    
    https://launchpad.net/bugs/1471258

diff --git a/units/emergency.service.in b/units/emergency.service.in
index 52b9b1c..8dc3cbd 100644
--- a/units/emergency.service.in
+++ b/units/emergency.service.in
@@ -16,7 +16,7 @@ Before=shutdown.target
 [Service]
 Environment=HOME=/root
 WorkingDirectory=/root
-ExecStartPre=-/bin/plymouth quit
+ExecStartPre=-/bin/plymouth --wait quit
 ExecStartPre=-/bin/echo -e 'Welcome to emergency mode! After logging in, type "journalctl -xb" to view\\nsystem logs, "systemctl reboot" to reboot, "systemctl default" or ^D to\\ntry again to boot into default mode.'
 ExecStart=-/bin/sh -c "@SULOGIN@; @SYSTEMCTL@ --job-mode=fail --no-block default"
 Type=idle

commit 43694a8cc70667498f3ffc5d9325b7d0428558e5
Merge: 0aa7a4c 59658d1
Author: Lennart Poettering <lennart at poettering.net>
Date:   Thu Jul 9 11:50:03 2015 -0300

    Merge pull request #531 from dvdhrm/boot-buildid
    
    boot: use BUILD_ID if VERSION_ID is not available


commit 0aa7a4c2258c867d972b6df9b500674596975d88
Merge: ac52135 92d16a5
Author: Lennart Poettering <lennart at poettering.net>
Date:   Thu Jul 9 11:47:55 2015 -0300

    Merge pull request #532 from dvdhrm/bus-managed-root
    
    sd-bus: include queried path in GetManagedObjects


commit ac5213569cd670131e2120f6f244108080818d6b
Author: cee1 <fykcee1 at gmail.com>
Date:   Thu Jul 9 13:52:16 2015 +0800

    basic/util.c fopen_temporary(): close fd if failed

diff --git a/src/basic/util.c b/src/basic/util.c
index e4e302a..c88cd1d 100644
--- a/src/basic/util.c
+++ b/src/basic/util.c
@@ -2535,6 +2535,7 @@ int fopen_temporary(const char *path, FILE **_f, char **_temp_path) {
         if (!f) {
                 unlink(t);
                 free(t);
+                safe_close(fd);
                 return -errno;
         }
 

commit d711ea2b95279b33c53e535723515b70bddbcc75
Merge: 254214b 839b6db
Author: Lennart Poettering <lennart at poettering.net>
Date:   Thu Jul 9 11:38:11 2015 -0300

    Merge pull request #529 from dvdhrm/bus-slot-description
    
    sd-bus: sd_bus_slot_get_description() should return const strings


commit 254214bfcdf2026ea74dd9d69690d89b7ea9cd39
Merge: a0f7095 06af2a0
Author: Daniel Mack <github at zonque.org>
Date:   Thu Jul 9 10:01:06 2015 -0400

    Merge pull request #426 from tblume/reload-system-conf-at-daemon-reload
    
    Reload manager defaults at daemon-reload


commit 92d16a53e385781a55d9231d9f8f89c1747ab0e4
Author: David Herrmann <dh.herrmann at gmail.com>
Date:   Thu Jul 9 13:27:57 2015 +0200

    sd-bus: include queried path in GetManagedObjects
    
    If GetManagedObjects is called on /foo/bar, then it should also include
    the object /foo/bar, if it exists. Right now, we only include objects
    underneath /foo/bar/.
    
    This follows the behavior of existing dbus implementations.
    
    Obsoletes #527 and fixes #525. Reported by: Nathaniel McCallum

diff --git a/src/libsystemd/sd-bus/bus-objects.c b/src/libsystemd/sd-bus/bus-objects.c
index 2eaa7de..b3cc28e 100644
--- a/src/libsystemd/sd-bus/bus-objects.c
+++ b/src/libsystemd/sd-bus/bus-objects.c
@@ -1164,6 +1164,10 @@ static int process_get_managed_objects(
         if (bus->nodes_modified)
                 return 0;
 
+        r = set_put_strdup(s, m->path);
+        if (r < 0)
+                return r;
+
         r = sd_bus_message_new_method_return(m, &reply);
         if (r < 0)
                 return r;
diff --git a/src/libsystemd/sd-bus/test-bus-objects.c b/src/libsystemd/sd-bus/test-bus-objects.c
index 5295260..1db67ec 100644
--- a/src/libsystemd/sd-bus/test-bus-objects.c
+++ b/src/libsystemd/sd-bus/test-bus-objects.c
@@ -115,14 +115,13 @@ static int set_handler(sd_bus *bus, const char *path, const char *interface, con
 
 static int value_handler(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error) {
         _cleanup_free_ char *s = NULL;
-        const char *x;
         int r;
 
         assert_se(asprintf(&s, "object %p, path %s", userdata, path) >= 0);
         r = sd_bus_message_append(reply, "s", s);
         assert_se(r >= 0);
 
-        assert_se(x = startswith(path, "/value/"));
+        assert_se(startswith(path, "/value/") != NULL || strcmp(path, "/value") == 0);
 
         assert_se(PTR_TO_UINT(userdata) == 30);
 

commit 59658d1958a7990722240e23c25163e98aa013c8
Author: David Herrmann <dh.herrmann at gmail.com>
Date:   Thu Jul 9 13:04:58 2015 +0200

    boot: use BUILD_ID if VERSION_ID is not present
    
    According to os-release(5), VERSION_ID is not mandatory and BUILD_ID only
    needs to be unique underneath VERSION_ID. Therefore, assuming a missing
    VERSION_ID field means 'empty', we can rely on BUILD_ID to be unique.
    
    Use BUILD_ID if VERSION_ID is not present. This way, rolling-release
    distros can still provide a proper os-release entry without crafting
    random VERSION_ID strings.
    
    This fixes #186.

diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c
index 861adff..827c118 100644
--- a/src/boot/efi/boot.c
+++ b/src/boot/efi/boot.c
@@ -1517,6 +1517,7 @@ static VOID config_entry_add_linux( Config *config, EFI_LOADED_IMAGE *loaded_ima
                         CHAR16 *os_name = NULL;
                         CHAR16 *os_id = NULL;
                         CHAR16 *os_version = NULL;
+                        CHAR16 *os_build = NULL;
 
                         bufsize = sizeof(buf);
                         err = uefi_call_wrapper(linux_dir->Read, 3, linux_dir, &bufsize, buf);
@@ -1563,13 +1564,19 @@ static VOID config_entry_add_linux( Config *config, EFI_LOADED_IMAGE *loaded_ima
                                         os_version = stra_to_str(value);
                                         continue;
                                 }
+
+                                if (strcmpa((CHAR8 *)"BUILD_ID", key) == 0) {
+                                        FreePool(os_build);
+                                        os_build = stra_to_str(value);
+                                        continue;
+                                }
                         }
 
-                        if (os_name && os_id && os_version) {
+                        if (os_name && os_id && (os_version || os_build)) {
                                 CHAR16 *conf;
                                 CHAR16 *path;
 
-                                conf = PoolPrint(L"%s-%s", os_id, os_version);
+                                conf = PoolPrint(L"%s-%s", os_id, os_version ? : os_build);
                                 path = PoolPrint(L"\\EFI\\Linux\\%s", f->FileName);
                                 config_entry_add_loader(config, loaded_image->DeviceHandle, LOADER_LINUX, conf, 'l', os_name, path);
                                 FreePool(conf);
@@ -1579,6 +1586,7 @@ static VOID config_entry_add_linux( Config *config, EFI_LOADED_IMAGE *loaded_ima
                         FreePool(os_name);
                         FreePool(os_id);
                         FreePool(os_version);
+                        FreePool(os_build);
                         FreePool(content);
                 }
                 uefi_call_wrapper(linux_dir->Close, 1, linux_dir);

commit d8c64b7f90b053d7bdf8d83133d9a4cc5be788dd
Author: David Herrmann <dh.herrmann at gmail.com>
Date:   Thu Jul 9 13:02:54 2015 +0200

    boot: fix memleaks in os-release parser
    
    There is no guarantee that the os-release section contains each key only
    once, nor any guarantee that all keys are present. Make sure we properly
    free memory in both cases.
    
    Not that it matters much, as we're short-living, anyway. But correct code
    is always nicer to read..

diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c
index eb1a4e3..861adff 100644
--- a/src/boot/efi/boot.c
+++ b/src/boot/efi/boot.c
@@ -1547,16 +1547,19 @@ static VOID config_entry_add_linux( Config *config, EFI_LOADED_IMAGE *loaded_ima
                         line = content;
                         while ((line = line_get_key_value(content, (CHAR8 *)"=", &pos, &key, &value))) {
                                 if (strcmpa((CHAR8 *)"PRETTY_NAME", key) == 0) {
+                                        FreePool(os_name);
                                         os_name = stra_to_str(value);
                                         continue;
                                 }
 
                                 if (strcmpa((CHAR8 *)"ID", key) == 0) {
+                                        FreePool(os_id);
                                         os_id = stra_to_str(value);
                                         continue;
                                 }
 
                                 if (strcmpa((CHAR8 *)"VERSION_ID", key) == 0) {
+                                        FreePool(os_version);
                                         os_version = stra_to_str(value);
                                         continue;
                                 }
@@ -1571,11 +1574,11 @@ static VOID config_entry_add_linux( Config *config, EFI_LOADED_IMAGE *loaded_ima
                                 config_entry_add_loader(config, loaded_image->DeviceHandle, LOADER_LINUX, conf, 'l', os_name, path);
                                 FreePool(conf);
                                 FreePool(path);
-                                FreePool(os_name);
-                                FreePool(os_id);
-                                FreePool(os_version);
                         }
 
+                        FreePool(os_name);
+                        FreePool(os_id);
+                        FreePool(os_version);
                         FreePool(content);
                 }
                 uefi_call_wrapper(linux_dir->Close, 1, linux_dir);

commit fbbf7a90ccf353e21f066fc90ab6fa18e3aa7ba3
Author: David Herrmann <dh.herrmann at gmail.com>
Date:   Thu Jul 9 11:37:26 2015 +0200

    resolve-host: enable dbus-activation
    
    Right now, systemd-resolve-host fails if resolved is not running.
    However, resolved supports bus-activation (at least on kdbus) just fine.
    Enable this so we can use resolve-host at all times.
    
    This was disabled right from the beginning, without any comment why.

diff --git a/src/resolve-host/resolve-host.c b/src/resolve-host/resolve-host.c
index f9448e3..0edba41 100644
--- a/src/resolve-host/resolve-host.c
+++ b/src/resolve-host/resolve-host.c
@@ -89,10 +89,6 @@ static int resolve_host(sd_bus *bus, const char *name) {
         if (r < 0)
                 return bus_log_create_error(r);
 
-        r = sd_bus_message_set_auto_start(req, false);
-        if (r < 0)
-                return bus_log_create_error(r);
-
         r = sd_bus_message_append(req, "isit", arg_ifindex, name, arg_family, arg_flags);
         if (r < 0)
                 return bus_log_create_error(r);

commit 839b6dbba9a6e4f08ddc2ae6d2b2b260d76f7c74
Author: David Herrmann <dh.herrmann at gmail.com>
Date:   Thu Jul 9 10:40:41 2015 +0200

    sd-bus: sd_bus_slot_get_description() should return const strings
    
    All other *_get_description() functions use 'const char**', so make sure
    sd_bus_slot_get_description() does the same.
    
    This changes API, but ABI stays stable. I think this is fine, but I
    wouldn't mind bumping SONAME.
    
    Reported in #528.

diff --git a/src/libsystemd/sd-bus/bus-slot.c b/src/libsystemd/sd-bus/bus-slot.c
index c452477..b149ea1 100644
--- a/src/libsystemd/sd-bus/bus-slot.c
+++ b/src/libsystemd/sd-bus/bus-slot.c
@@ -273,7 +273,7 @@ _public_ int sd_bus_slot_set_description(sd_bus_slot *slot, const char *descript
         return free_and_strdup(&slot->description, description);
 }
 
-_public_ int sd_bus_slot_get_description(sd_bus_slot *slot, char **description) {
+_public_ int sd_bus_slot_get_description(sd_bus_slot *slot, const char **description) {
         assert_return(slot, -EINVAL);
         assert_return(description, -EINVAL);
         assert_return(slot->description, -ENXIO);
diff --git a/src/systemd/sd-bus.h b/src/systemd/sd-bus.h
index f348931..5439a19 100644
--- a/src/systemd/sd-bus.h
+++ b/src/systemd/sd-bus.h
@@ -205,7 +205,7 @@ sd_bus* sd_bus_slot_get_bus(sd_bus_slot *slot);
 void *sd_bus_slot_get_userdata(sd_bus_slot *slot);
 void *sd_bus_slot_set_userdata(sd_bus_slot *slot, void *userdata);
 int sd_bus_slot_set_description(sd_bus_slot *slot, const char *description);
-int sd_bus_slot_get_description(sd_bus_slot *slot, char **description);
+int sd_bus_slot_get_description(sd_bus_slot *slot, const char **description);
 
 sd_bus_message* sd_bus_slot_get_current_message(sd_bus_slot *slot);
 sd_bus_message_handler_t sd_bus_slot_get_current_handler(sd_bus_slot *bus);

commit 06af2a04fb34c3e8f99734571c0c5d2203d6a265
Author: Thomas Blume <Thomas.Blume at suse.com>
Date:   Mon Jun 29 11:26:27 2015 +0200

    Reload manager defaults at daemon-reload
    
    "systemctl daemon-reload" should also update the manager defaults from
    /etc/systemd/system.conf.
    For details, see:
    http://lists.freedesktop.org/archives/systemd-devel/2015-June/033062.html
    
    Amended to use  manager_set_defaults() as common function.

diff --git a/src/core/main.c b/src/core/main.c
index c412457..6ae8b51 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -685,6 +685,26 @@ static int parse_config_file(void) {
         return 0;
 }
 
+static void manager_set_defaults(Manager *m) {
+
+        assert(m);
+
+        m->default_timer_accuracy_usec = arg_default_timer_accuracy_usec;
+        m->default_std_output = arg_default_std_output;
+        m->default_std_error = arg_default_std_error;
+        m->default_timeout_start_usec = arg_default_timeout_start_usec;
+        m->default_timeout_stop_usec = arg_default_timeout_stop_usec;
+        m->default_restart_usec = arg_default_restart_usec;
+        m->default_start_limit_interval = arg_default_start_limit_interval;
+        m->default_start_limit_burst = arg_default_start_limit_burst;
+        m->default_cpu_accounting = arg_default_cpu_accounting;
+        m->default_blockio_accounting = arg_default_blockio_accounting;
+        m->default_memory_accounting = arg_default_memory_accounting;
+
+        manager_set_default_rlimits(m, arg_default_rlimit);
+        manager_environment_add(m, NULL, arg_default_environment);
+}
+
 static int parse_argv(int argc, char *argv[]) {
 
         enum {
@@ -1630,28 +1650,15 @@ int main(int argc, char *argv[]) {
         }
 
         m->confirm_spawn = arg_confirm_spawn;
-        m->default_timer_accuracy_usec = arg_default_timer_accuracy_usec;
-        m->default_std_output = arg_default_std_output;
-        m->default_std_error = arg_default_std_error;
-        m->default_restart_usec = arg_default_restart_usec;
-        m->default_timeout_start_usec = arg_default_timeout_start_usec;
-        m->default_timeout_stop_usec = arg_default_timeout_stop_usec;
-        m->default_start_limit_interval = arg_default_start_limit_interval;
-        m->default_start_limit_burst = arg_default_start_limit_burst;
-        m->default_cpu_accounting = arg_default_cpu_accounting;
-        m->default_blockio_accounting = arg_default_blockio_accounting;
-        m->default_memory_accounting = arg_default_memory_accounting;
         m->runtime_watchdog = arg_runtime_watchdog;
         m->shutdown_watchdog = arg_shutdown_watchdog;
-
         m->userspace_timestamp = userspace_timestamp;
         m->kernel_timestamp = kernel_timestamp;
         m->initrd_timestamp = initrd_timestamp;
         m->security_start_timestamp = security_start_timestamp;
         m->security_finish_timestamp = security_finish_timestamp;
 
-        manager_set_default_rlimits(m, arg_default_rlimit);
-        manager_environment_add(m, NULL, arg_default_environment);
+        manager_set_defaults(m);
         manager_set_show_status(m, arg_show_status);
         manager_set_first_boot(m, empty_etc);
 
@@ -1763,6 +1770,13 @@ int main(int argc, char *argv[]) {
 
                 case MANAGER_RELOAD:
                         log_info("Reloading.");
+
+                        r = parse_config_file();
+                        if (r < 0)
+                                log_error("Failed to parse config file.");
+
+                        manager_set_defaults(m);
+
                         r = manager_reload(m);
                         if (r < 0)
                                 log_error_errno(r, "Failed to reload: %m");

commit 4c641e99fa1b32385b941cccccb566f5ddc9daed
Author: Tom Gundersen <teg at jklm.no>
Date:   Tue Jun 23 13:13:20 2015 +0200

    sd-netlink: respect attribute type flags
    
    Though currently unused by us, netlink attribute types support embedding flags to indicate
    if the type is encoded in network byte-order and if it is a nested attribute. Read out
    these flags when parsing the message.
    
    We will now swap the byteorder in case it is non-native when reading out integers (though
    this is not needed by any of the types we currently support). We do not enforce the NESTED
    flag, as the kernel gets this wrong in many cases.

diff --git a/src/libsystemd/sd-netlink/netlink-internal.h b/src/libsystemd/sd-netlink/netlink-internal.h
index b8a3668..4aa7583 100644
--- a/src/libsystemd/sd-netlink/netlink-internal.h
+++ b/src/libsystemd/sd-netlink/netlink-internal.h
@@ -94,6 +94,8 @@ struct sd_netlink {
 
 struct netlink_attribute {
         size_t offset; /* offset from hdr to attirubte */
+        bool nested:1;
+        bool net_byteorder:1;
 };
 
 struct netlink_container {
diff --git a/src/libsystemd/sd-netlink/netlink-message.c b/src/libsystemd/sd-netlink/netlink-message.c
index 13573dc..b0ed2f2 100644
--- a/src/libsystemd/sd-netlink/netlink-message.c
+++ b/src/libsystemd/sd-netlink/netlink-message.c
@@ -38,6 +38,7 @@
 #define PUSH_CONTAINER(m, new) (m)->container_offsets[(m)->n_containers ++] = (uint8_t*)(new) - (uint8_t*)(m)->hdr;
 
 #define RTA_TYPE(rta) ((rta)->rta_type & NLA_TYPE_MASK)
+#define RTA_FLAGS(rta) ((rta)->rta_type & ~NLA_TYPE_MASK)
 
 int message_new_empty(sd_netlink *rtnl, sd_netlink_message **ret) {
         sd_netlink_message *m;
@@ -475,7 +476,7 @@ int sd_netlink_message_close_container(sd_netlink_message *m) {
         return 0;
 }
 
-static int netlink_message_read_internal(sd_netlink_message *m, unsigned short type, void **data) {
+static int netlink_message_read_internal(sd_netlink_message *m, unsigned short type, void **data, bool *net_byteorder) {
         struct netlink_attribute *attribute;
         struct rtattr *rta;
 
@@ -495,6 +496,9 @@ static int netlink_message_read_internal(sd_netlink_message *m, unsigned short t
 
         *data = RTA_DATA(rta);
 
+        if (net_byteorder)
+                *net_byteorder = attribute->net_byteorder;
+
         return RTA_PAYLOAD(rta);
 }
 
@@ -508,7 +512,7 @@ int sd_netlink_message_read_string(sd_netlink_message *m, unsigned short type, c
         if (r < 0)
                 return r;
 
-        r = netlink_message_read_internal(m, type, &attr_data);
+        r = netlink_message_read_internal(m, type, &attr_data, NULL);
         if (r < 0)
                 return r;
         else if (strnlen(attr_data, r) >= (size_t) r)
@@ -530,7 +534,7 @@ int sd_netlink_message_read_u8(sd_netlink_message *m, unsigned short type, uint8
         if (r < 0)
                 return r;
 
-        r = netlink_message_read_internal(m, type, &attr_data);
+        r = netlink_message_read_internal(m, type, &attr_data, NULL);
         if (r < 0)
                 return r;
         else if ((size_t) r < sizeof(uint8_t))
@@ -543,8 +547,9 @@ int sd_netlink_message_read_u8(sd_netlink_message *m, unsigned short type, uint8
 }
 
 int sd_netlink_message_read_u16(sd_netlink_message *m, unsigned short type, uint16_t *data) {
-        int r;
         void *attr_data;
+        bool net_byteorder;
+        int r;
 
         assert_return(m, -EINVAL);
 
@@ -552,21 +557,26 @@ int sd_netlink_message_read_u16(sd_netlink_message *m, unsigned short type, uint
         if (r < 0)
                 return r;
 
-        r = netlink_message_read_internal(m, type, &attr_data);
+        r = netlink_message_read_internal(m, type, &attr_data, &net_byteorder);
         if (r < 0)
                 return r;
         else if ((size_t) r < sizeof(uint16_t))
                 return -EIO;
 
-        if (data)
-                *data = *(uint16_t *) attr_data;
+        if (data) {
+                if (net_byteorder)
+                        *data = be16toh(*(uint16_t *) attr_data);
+                else
+                        *data = *(uint16_t *) attr_data;
+        }
 
         return 0;
 }
 
 int sd_netlink_message_read_u32(sd_netlink_message *m, unsigned short type, uint32_t *data) {
-        int r;
         void *attr_data;
+        bool net_byteorder;
+        int r;
 
         assert_return(m, -EINVAL);
 
@@ -574,14 +584,18 @@ int sd_netlink_message_read_u32(sd_netlink_message *m, unsigned short type, uint
         if (r < 0)
                 return r;
 
-        r = netlink_message_read_internal(m, type, &attr_data);
+        r = netlink_message_read_internal(m, type, &attr_data, &net_byteorder);
         if (r < 0)
                 return r;
         else if ((size_t)r < sizeof(uint32_t))
                 return -EIO;
 
-        if (data)
-                *data = *(uint32_t *) attr_data;
+        if (data) {
+                if (net_byteorder)
+                        *data = be32toh(*(uint32_t *) attr_data);
+                else
+                        *data = *(uint32_t *) attr_data;
+        }
 
         return 0;
 }
@@ -596,7 +610,7 @@ int sd_netlink_message_read_ether_addr(sd_netlink_message *m, unsigned short typ
         if (r < 0)
                 return r;
 
-        r = netlink_message_read_internal(m, type, &attr_data);
+        r = netlink_message_read_internal(m, type, &attr_data, NULL);
         if (r < 0)
                 return r;
         else if ((size_t)r < sizeof(struct ether_addr))
@@ -618,7 +632,7 @@ int sd_netlink_message_read_cache_info(sd_netlink_message *m, unsigned short typ
         if (r < 0)
                 return r;
 
-        r = netlink_message_read_internal(m, type, &attr_data);
+        r = netlink_message_read_internal(m, type, &attr_data, NULL);
         if (r < 0)
                 return r;
         else if ((size_t)r < sizeof(struct ifa_cacheinfo))
@@ -640,7 +654,7 @@ int sd_netlink_message_read_in_addr(sd_netlink_message *m, unsigned short type,
         if (r < 0)
                 return r;
 
-        r = netlink_message_read_internal(m, type, &attr_data);
+        r = netlink_message_read_internal(m, type, &attr_data, NULL);
         if (r < 0)
                 return r;
         else if ((size_t)r < sizeof(struct in_addr))
@@ -662,7 +676,7 @@ int sd_netlink_message_read_in6_addr(sd_netlink_message *m, unsigned short type,
         if (r < 0)
                 return r;
 
-        r = netlink_message_read_internal(m, type, &attr_data);
+        r = netlink_message_read_internal(m, type, &attr_data, NULL);
         if (r < 0)
                 return r;
         else if ((size_t)r < sizeof(struct in6_addr))
@@ -699,6 +713,8 @@ static int netlink_container_parse(sd_netlink_message *m,
                         log_debug("rtnl: message parse - overwriting repeated attribute");
 
                 attributes[type].offset = (uint8_t *) rta - (uint8_t *) m->hdr;
+                attributes[type].nested = RTA_FLAGS(rta) & NLA_F_NESTED;
+                attributes[type].net_byteorder = RTA_FLAGS(rta) & NLA_F_NET_BYTEORDER;
         }
 
         container->attributes = attributes;
@@ -781,7 +797,7 @@ int sd_netlink_message_enter_container(sd_netlink_message *m, unsigned short typ
         } else
                 return -EINVAL;
 
-        r = netlink_message_read_internal(m, type_id, &container);
+        r = netlink_message_read_internal(m, type_id, &container, NULL);
         if (r < 0)
                 return r;
         else



More information about the systemd-commits mailing list