]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
rfc3046 implementation
authorYegor Alexeyev <yegor.alexeyev@gmail.com>
Wed, 21 Apr 2021 03:51:07 +0000 (06:51 +0300)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Sat, 8 May 2021 06:59:29 +0000 (15:59 +0900)
16 files changed:
man/systemd.network.xml
src/libsystemd-network/dhcp-internal.h
src/libsystemd-network/dhcp-option.c
src/libsystemd-network/dhcp-server-internal.h
src/libsystemd-network/sd-dhcp-server.c
src/libsystemd-network/test-dhcp-option.c
src/network/networkd-dhcp-server.c
src/network/networkd-dhcp-server.h
src/network/networkd-network-gperf.gperf
src/network/networkd-network.c
src/network/networkd-network.h
src/systemd/sd-dhcp-client.h
src/systemd/sd-dhcp-server.h
test/fuzz/fuzz-network-parser/directives.network
test/test-network/conf/agent-client-peer.network
test/test-network/systemd-networkd-tests.py

index 7f137db2231cd10dddcf1efa29234e8289643dee..5c1c6e118eeed0785a0997c9e62f05fb2de05fd3 100644 (file)
@@ -2325,17 +2325,6 @@ IPv6Token=prefixstable:2002:da8:1::</programlisting></para>
 
     <variablelist class='network-directives'>
 
-      <varlistentry>
-        <term><varname>RelayTarget=</varname></term>
-        <listitem>
-          <para>Takes an IPv4 address, which must be in the format
-          described in
-          <citerefentry project='man-pages'><refentrytitle>inet_pton</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
-          Turns this DHCP server into a DHCP relay agent. See <ulink url="https://tools.ietf.org/html/rfc1542">RFC 1542</ulink>.
-          The address is the address of DHCP server or another relay agent to forward DHCP messages to and from.</para>
-          Check also BindToInterface= option. Turning it off is required for relaying messages outside.
-        </listitem>
-      </varlistentry>
       <varlistentry>
         <term><varname>PoolOffset=</varname></term>
         <term><varname>PoolSize=</varname></term>
@@ -2461,9 +2450,40 @@ IPv6Token=prefixstable:2002:da8:1::</programlisting></para>
       </varlistentry>
       <varlistentry>
         <term><varname>BindToInterface=</varname></term>
-        <listitem>Takes a boolean value. When <literal>yes</literal>, DHCP server socket will be bound
-        to its network interface and all socket communication will be restricted to this interface.
-        Defaults to <literal>yes</literal>.
+        <listitem>
+          <para>Takes a boolean value. When <literal>yes</literal>, DHCP server socket will be bound
+          to its network interface and all socket communication will be restricted to this interface.
+          Defaults to <literal>yes</literal>, except if <varname>RelayTarget=</varname> is used (see below),
+          in which case it defaults defaults to <literal>no</literal>.</para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><varname>RelayTarget=</varname></term>
+        <listitem>
+          <para>Takes an IPv4 address, which must be in the format described in
+          <citerefentry project='man-pages'><refentrytitle>inet_pton</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
+          Turns this DHCP server into a DHCP relay agent. See <ulink url="https://tools.ietf.org/html/rfc1542">RFC 1542</ulink>.
+          The address is the address of DHCP server or another relay agent to forward DHCP messages to and from.</para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><varname>RelayAgentCircuitId=</varname></term>
+        <listitem>
+          <para>Specifies value for Agent Circuit ID suboption of Relay Agent Information option.
+          Takes a string, which must be in the format <literal>string:<replaceable>value</replaceable></literal>,
+          where <literal><replaceable>value</replaceable></literal> should be replaced with the value of the suboption.
+          Defaults to unset (means no Agent Circuit ID suboption is generated).
+          Ignored if <varname>RelayTarget=</varname> is not specified.</para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><varname>RelayAgentRemoteId=</varname></term>
+        <listitem>
+          <para>Specifies value for Agent Remote ID suboption of Relay Agent Information option.
+          Takes a string, which must be in the format <literal>string:<replaceable>value</replaceable></literal>,
+          where <literal><replaceable>value</replaceable></literal> should be replaced with the value of the suboption.
+          Defaults to unset (means no Agent Remote ID suboption is generated).
+          Ignored if <varname>RelayTarget=</varname> is not specified.</para>
         </listitem>
       </varlistentry>
 
index e5be7c5a63b5dab09b6895feb5af6c0fabd64788..d8c42757aa62f45581fa753dd1141d6f18a1e232 100644 (file)
@@ -42,6 +42,8 @@ int dhcp_network_send_udp_socket(int s, be32_t address, uint16_t port,
 
 int dhcp_option_append(DHCPMessage *message, size_t size, size_t *offset, uint8_t overload,
                        uint8_t code, size_t optlen, const void *optval);
+int dhcp_option_find_option(uint8_t *options, size_t length, uint8_t wanted_code, size_t *ret_offset);
+int dhcp_option_remove_option(uint8_t *options, size_t buflen, uint8_t option_code);
 
 typedef int (*dhcp_option_callback_t)(uint8_t code, uint8_t len,
                                 const void *option, void *userdata);
index 8899e8a55239db3db2c32335f6b4152a70e1a4fd..ebe8eecc9dbf592561856be001f7000d5e43050c 100644 (file)
 #include "strv.h"
 #include "utf8.h"
 
+/* Append type-length value structure to the options buffer */
+static int dhcp_option_append_tlv(uint8_t options[], size_t size, size_t *offset, uint8_t code, size_t optlen, const void *optval) {
+        assert(options);
+        assert(size > 0);
+        assert(offset);
+        assert(optlen <= UINT8_MAX);
+        assert(*offset < size);
+
+        if (*offset + 2 + optlen > size)
+                return -ENOBUFS;
+
+        options[*offset] = code;
+        options[*offset + 1] = optlen;
+
+        memcpy_safe(&options[*offset + 2], optval, optlen);
+        *offset += 2 + optlen;
+        return 0;
+}
+
 static int option_append(uint8_t options[], size_t size, size_t *offset,
                          uint8_t code, size_t optlen, const void *optval) {
         assert(options);
         assert(size > 0);
         assert(offset);
 
+        int r;
+
         if (code != SD_DHCP_OPTION_END)
                 /* always make sure there is space for an END option */
                 size--;
@@ -93,32 +114,91 @@ static int option_append(uint8_t options[], size_t size, size_t *offset,
 
                 options[*offset] = code;
                 options[*offset + 1] = l;
-
                 *offset += 2;
 
                 ORDERED_SET_FOREACH(p, s) {
-                        options[*offset] = p->option;
-                        options[*offset + 1] = p->length;
-                        memcpy(&options[*offset + 2], p->data, p->length);
-                        *offset += 2 + p->length;
+                        r = dhcp_option_append_tlv(options, size, offset, p->option, p->length, p->data);
+                        if (r < 0)
+                                return r;
                 }
+                break;
+        }
+        case SD_DHCP_OPTION_RELAY_AGENT_INFORMATION: {
+                sd_dhcp_server *server = (sd_dhcp_server *) optval;
+                size_t current_offset = *offset + 2;
 
+                if (server->agent_circuit_id) {
+                        r = dhcp_option_append_tlv(options, size, &current_offset, SD_DHCP_RELAY_AGENT_CIRCUIT_ID,
+                                                   strlen(server->agent_circuit_id), server->agent_circuit_id);
+                        if (r < 0)
+                                return r;
+                }
+                if (server->agent_remote_id) {
+                        r = dhcp_option_append_tlv(options, size, &current_offset, SD_DHCP_RELAY_AGENT_REMOTE_ID,
+                                                   strlen(server->agent_remote_id), server->agent_remote_id);
+                        if (r < 0)
+                                return r;
+                }
+
+                options[*offset] = code;
+                options[*offset + 1] = current_offset - *offset - 2;
+                assert(current_offset - *offset - 2 <= UINT8_MAX);
+                *offset = current_offset;
                 break;
         }
         default:
-                if (*offset + 2 + optlen > size)
-                        return -ENOBUFS;
+                return dhcp_option_append_tlv(options, size, offset, code, optlen, optval);
+        }
+        return 0;
+}
 
-                options[*offset] = code;
-                options[*offset + 1] = optlen;
+static int option_length(uint8_t *options, size_t length, size_t offset) {
+        assert(options);
+        assert(offset < length);
 
-                memcpy_safe(&options[*offset + 2], optval, optlen);
-                *offset += 2 + optlen;
+        if (IN_SET(options[offset], SD_DHCP_OPTION_PAD, SD_DHCP_OPTION_END))
+                return 1;
+        if (length < offset + 2)
+                return -ENOBUFS;
 
-                break;
+        /* validating that buffer is long enough */
+        if (length < offset + 2 + options[offset + 1])
+                return -ENOBUFS;
+
+        return options[offset + 1] + 2;
+}
+
+int dhcp_option_find_option(uint8_t *options, size_t length, uint8_t code, size_t *ret_offset) {
+        int r;
+
+        assert(options);
+        assert(ret_offset);
+
+        for (size_t offset = 0; offset < length; offset += r) {
+                r = option_length(options, length, offset);
+                if (r < 0)
+                        return r;
+
+                if (code == options[offset]) {
+                        *ret_offset = offset;
+                        return r;
+                }
         }
+        return -ENOENT;
+}
 
-        return 0;
+int dhcp_option_remove_option(uint8_t *options, size_t length, uint8_t option_code) {
+        int r;
+        size_t offset;
+
+        assert(options);
+
+        r = dhcp_option_find_option(options, length, option_code, &offset);
+        if (r < 0)
+                return r;
+
+        memmove(options + offset, options + offset + r, length - offset - r);
+        return length - r;
 }
 
 int dhcp_option_append(DHCPMessage *message, size_t size, size_t *offset,
index 3628223ae9ac47cd78d76a444fbec7ab4674b788..088155d6f1352591e5a160f4f14ec15251e6476e 100644 (file)
@@ -39,7 +39,6 @@ typedef struct DHCPLease {
 } DHCPLease;
 
 struct sd_dhcp_server {
-        struct in_addr relay_target;
         unsigned n_ref;
 
         sd_event *event;
@@ -76,6 +75,11 @@ struct sd_dhcp_server {
 
         sd_dhcp_server_callback_t callback;
         void *callback_userdata;
+
+        struct in_addr relay_target;
+
+        char *agent_circuit_id;
+        char *agent_remote_id;
 };
 
 typedef struct DHCPRequest {
@@ -88,6 +92,7 @@ typedef struct DHCPRequest {
         be32_t server_id;
         be32_t requested_ip;
         uint32_t lifetime;
+        const uint8_t *agent_info_option;
 } DHCPRequest;
 
 int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message,
index e2ad99ebcbdec265069b384efe5c39ff41be5903..05c8a0eae4b1c79bdaaa9daa50ad636c5378783c 100644 (file)
@@ -164,6 +164,9 @@ static sd_dhcp_server *dhcp_server_free(sd_dhcp_server *server) {
         ordered_set_free(server->extra_options);
         ordered_set_free(server->vendor_options);
 
+        free(server->agent_circuit_id);
+        free(server->agent_remote_id);
+
         free(server->bound_leases);
 
         free(server->ifname);
@@ -382,6 +385,7 @@ int dhcp_server_send_packet(sd_dhcp_server *server,
         assert(server);
         assert(req);
         assert(req->max_optlen);
+        assert(req->message);
         assert(optoffset <= req->max_optlen);
         assert(packet);
 
@@ -391,6 +395,15 @@ int dhcp_server_send_packet(sd_dhcp_server *server,
         if (r < 0)
                 return r;
 
+        if (req->agent_info_option) {
+                size_t opt_full_length = *(req->agent_info_option + 1) + 2;
+                /* there must be space left for SD_DHCP_OPTION_END */
+                if (optoffset + opt_full_length < req->max_optlen) {
+                        memcpy(packet->dhcp.options + optoffset, req->agent_info_option, opt_full_length);
+                        optoffset += opt_full_length;
+                }
+        }
+
         r = dhcp_option_append(&packet->dhcp, req->max_optlen, &optoffset, 0,
                                SD_DHCP_OPTION_END, 0, NULL);
         if (r < 0)
@@ -649,6 +662,10 @@ static int parse_request(uint8_t code, uint8_t len, const void *option, void *us
                 if (len == 2 && unaligned_read_be16(option) >= sizeof(DHCPPacket))
                         req->max_optlen = unaligned_read_be16(option) - sizeof(DHCPPacket);
 
+                break;
+        case SD_DHCP_OPTION_RELAY_AGENT_INFORMATION:
+                req->agent_info_option = (uint8_t*)option - 2;
+
                 break;
         }
 
@@ -712,8 +729,30 @@ static int get_pool_offset(sd_dhcp_server *server, be32_t requested_ip) {
         return be32toh(requested_ip & ~server->netmask) - server->pool_offset;
 }
 
-static int dhcp_server_relay_message(sd_dhcp_server *server, DHCPMessage *message, size_t opt_length) {
+static int append_agent_information_option(sd_dhcp_server *server, DHCPMessage *message, size_t opt_length, size_t size) {
+        int r;
+        size_t offset;
+
+        assert(server);
+        assert(message);
+
+        r = dhcp_option_find_option(message->options, opt_length, SD_DHCP_OPTION_END, &offset);
+        if (r < 0)
+                return r;
+
+        r = dhcp_option_append(message, size, &offset, 0, SD_DHCP_OPTION_RELAY_AGENT_INFORMATION, 0, server);
+        if (r < 0)
+                return r;
+
+        r = dhcp_option_append(message, size, &offset, 0, SD_DHCP_OPTION_END, 0, NULL);
+        if (r < 0)
+                return r;
+        return offset;
+}
+
+static int dhcp_server_relay_message(sd_dhcp_server *server, DHCPMessage *message, size_t opt_length, size_t buflen) {
         _cleanup_free_ DHCPPacket *packet = NULL;
+        int r;
 
         assert(server);
         assert(message);
@@ -729,13 +768,19 @@ static int dhcp_server_relay_message(sd_dhcp_server *server, DHCPMessage *messag
                 if (message->giaddr == 0)
                         message->giaddr = server->address;
 
+                if (server->agent_circuit_id || server->agent_remote_id) {
+                        r = append_agent_information_option(server, message, opt_length, buflen - sizeof(DHCPMessage));
+                        if (r < 0)
+                                return log_dhcp_server_errno(server, r, "could not append relay option: %m");
+                        opt_length = r;
+                }
+
                 return dhcp_server_send_udp(server, server->relay_target.s_addr, DHCP_PORT_SERVER, message, sizeof(DHCPMessage) + opt_length);
         } else if (message->op == BOOTREPLY) {
                 log_dhcp_server(server, "(relay agent) BOOTREPLY (0x%x)", be32toh(message->xid));
-                if (message->giaddr != server->address) {
+                if (message->giaddr != server->address)
                         return log_dhcp_server_errno(server, SYNTHETIC_ERRNO(EBADMSG),
-                                                     "(relay agent)  BOOTREPLY giaddr mismatch, discarding");
-                }
+                                                     "(relay agent) BOOTREPLY giaddr mismatch, discarding");
 
                 int message_type = dhcp_option_parse(message, sizeof(DHCPMessage) + opt_length, NULL, NULL, NULL);
                 if (message_type < 0)
@@ -746,6 +791,10 @@ static int dhcp_server_relay_message(sd_dhcp_server *server, DHCPMessage *messag
                         return -ENOMEM;
                 memcpy(&packet->dhcp, message, sizeof(DHCPMessage) + opt_length);
 
+                r = dhcp_option_remove_option(packet->dhcp.options, opt_length, SD_DHCP_OPTION_RELAY_AGENT_INFORMATION);
+                if (r > 0)
+                        opt_length = r;
+
                 bool l2_broadcast = requested_broadcast(message) || message_type == DHCP_NAK;
                 const be32_t destination = message_type == DHCP_NAK ? INADDR_ANY : message->ciaddr;
                 return dhcp_server_send(server, destination, DHCP_PORT_CLIENT, packet, opt_length, l2_broadcast);
@@ -1000,6 +1049,15 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message,
         return 0;
 }
 
+static size_t relay_agent_information_length(const char* agent_circuit_id, const char* agent_remote_id) {
+        size_t sum = 0;
+        if (agent_circuit_id)
+                sum += 2 + strlen(agent_circuit_id);
+        if (agent_remote_id)
+                sum += 2 + strlen(agent_remote_id);
+        return sum;
+}
+
 static int server_receive_message(sd_event_source *s, int fd,
                                   uint32_t revents, void *userdata) {
         _cleanup_free_ DHCPMessage *message = NULL;
@@ -1013,20 +1071,25 @@ static int server_receive_message(sd_event_source *s, int fd,
                 .msg_controllen = sizeof(control),
         };
         struct cmsghdr *cmsg;
-        ssize_t buflen, len;
+        ssize_t datagram_size, len;
         int r;
 
         assert(server);
 
-        buflen = next_datagram_size_fd(fd);
-        if (buflen < 0)
-                return buflen;
+        datagram_size = next_datagram_size_fd(fd);
+        if (datagram_size < 0)
+                return datagram_size;
+
+        size_t buflen = datagram_size;
+        if (sd_dhcp_server_is_in_relay_mode(server))
+                /* Preallocate the additional size for DHCP Relay Agent Information Option if neeeded */
+                buflen += relay_agent_information_length(server->agent_circuit_id, server->agent_remote_id) + 2;
 
         message = malloc(buflen);
         if (!message)
                 return -ENOMEM;
 
-        iov = IOVEC_MAKE(message, buflen);
+        iov = IOVEC_MAKE(message, datagram_size);
 
         len = recvmsg_safe(fd, &msg, 0);
         if (IN_SET(len, -EAGAIN, -EINTR))
@@ -1052,7 +1115,7 @@ static int server_receive_message(sd_event_source *s, int fd,
         }
 
         if (sd_dhcp_server_is_in_relay_mode(server)) {
-                r = dhcp_server_relay_message(server, message, len - sizeof(DHCPMessage));
+                r = dhcp_server_relay_message(server, message, len - sizeof(DHCPMessage), buflen);
                 if (r < 0)
                         log_dhcp_server_errno(server, r, "Couldn't relay message: %m");
         } else {
@@ -1296,7 +1359,7 @@ int sd_dhcp_server_set_callback(sd_dhcp_server *server, sd_dhcp_server_callback_
         return 0;
 }
 
-int sd_dhcp_server_set_relay_target(sd_dhcp_server *server, const struct in_addraddress) {
+int sd_dhcp_server_set_relay_target(sd_dhcp_server *server, const struct in_addr *address) {
         assert_return(server, -EINVAL);
         assert_return(!sd_dhcp_server_is_running(server), -EBUSY);
 
@@ -1306,3 +1369,31 @@ int sd_dhcp_server_set_relay_target(sd_dhcp_server *server, const struct in_addr
         server->relay_target = *address;
         return 1;
 }
+
+int sd_dhcp_server_set_relay_agent_information(
+                sd_dhcp_server *server,
+                const char *agent_circuit_id,
+                const char *agent_remote_id) {
+        _cleanup_free_ char *circuit_id_dup = NULL, *remote_id_dup = NULL;
+
+        assert_return(server, -EINVAL);
+
+        if (relay_agent_information_length(agent_circuit_id, agent_remote_id) > UINT8_MAX)
+                return -ENOBUFS;
+
+        if (agent_circuit_id) {
+                circuit_id_dup = strdup(agent_circuit_id);
+                if (!circuit_id_dup)
+                        return -ENOMEM;
+        }
+
+        if (agent_remote_id) {
+                remote_id_dup = strdup(agent_remote_id);
+                if (!remote_id_dup)
+                        return -ENOMEM;
+        }
+
+        free_and_replace(server->agent_circuit_id, circuit_id_dup);
+        free_and_replace(server->agent_remote_id, remote_id_dup);
+        return 0;
+}
index 1eebe3a10f95cf9249be62dd8e1b77913463bb70..d152e7925d75b4da59148987249eab0d3fda2291 100644 (file)
@@ -270,6 +270,14 @@ static void test_options(struct option_desc *desc) {
                 printf("DHCP type %s\n", dhcp_type(res));
 }
 
+static void test_option_removal(struct option_desc *desc) {
+        _cleanup_free_ DHCPMessage *message = create_message(&desc->options[0], desc->len, NULL, 0, NULL, 0);
+
+        assert_se(dhcp_option_parse(message, sizeof(DHCPMessage) + desc->len, NULL, NULL, NULL) >= 0);
+        assert_se((desc->len = dhcp_option_remove_option(message->options, desc->len, SD_DHCP_OPTION_MESSAGE_TYPE)) >= 0);
+        assert_se(dhcp_option_parse(message, sizeof(DHCPMessage) + desc->len, NULL, NULL, NULL) < 0);
+}
+
 static uint8_t options[64] = {
         'A', 'B', 'C', 'D',
         160, 2, 0x11, 0x12,
@@ -366,5 +374,12 @@ int main(int argc, char *argv[]) {
 
         test_option_set();
 
+        for (i = 0; i < ELEMENTSOF(option_tests); i++) {
+                struct option_desc *desc = &option_tests[i];
+                if (!desc->success || desc->snamelen > 0 || desc->filelen > 0)
+                        continue;
+                test_option_removal(desc);
+        }
+
         return 0;
 }
index bd368672da77ae25b1ac7fb2c251b8d20ee1890d..f1216183bf6a136d1ec5286fcfdad4a6ef090a30 100644 (file)
@@ -252,6 +252,7 @@ int dhcp4_server_configure(Link *link) {
         sd_dhcp_option *p;
         Link *uplink = NULL;
         Address *address;
+        bool bind_to_interface;
         int r;
 
         assert(link);
@@ -344,10 +345,6 @@ int dhcp4_server_configure(Link *link) {
                                                dhcp_lease_server_type_to_string(type));
         }
 
-        r = sd_dhcp_server_set_bind_to_interface(link->dhcp_server, link->network->dhcp_server_bind_to_interface);
-        if (r < 0)
-                return log_link_error_errno(link, r, "Failed to set interface binding for DHCP server: %m");
-
         r = sd_dhcp_server_set_emit_router(link->dhcp_server, link->network->dhcp_server_emit_router);
         if (r < 0)
                 return log_link_error_errno(link, r, "Failed to set router emission for DHCP server: %m");
@@ -356,6 +353,15 @@ int dhcp4_server_configure(Link *link) {
         if (r < 0)
                 return log_link_error_errno(link, r, "Failed to set relay target for DHCP server: %m");
 
+        bind_to_interface = sd_dhcp_server_is_in_relay_mode(link->dhcp_server) ? false : link->network->dhcp_server_bind_to_interface;
+        r = sd_dhcp_server_set_bind_to_interface(link->dhcp_server, bind_to_interface);
+        if (r < 0)
+                return log_link_error_errno(link, r, "Failed to set interface binding for DHCP server: %m");
+
+        r = sd_dhcp_server_set_relay_agent_information(link->dhcp_server, link->network->dhcp_server_relay_agent_circuit_id, link->network->dhcp_server_relay_agent_remote_id);
+        if (r < 0)
+                return log_link_error_errno(link, r, "Failed to set agent circuit/remote id for DHCP server: %m");
+
         if (link->network->dhcp_server_emit_timezone) {
                 _cleanup_free_ char *buffer = NULL;
                 const char *tz;
@@ -402,6 +408,40 @@ int dhcp4_server_configure(Link *link) {
         return 0;
 }
 
+int config_parse_dhcp_server_relay_agent_suboption(
+                const char *unit,
+                const char *filename,
+                unsigned line,
+                const char *section,
+                unsigned section_line,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        char **suboption_value = data;
+        char* p;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+
+
+        if (isempty(rvalue)) {
+                *suboption_value = mfree(*suboption_value);
+                return 0;
+        }
+
+        p = startswith(rvalue, "string:");
+        if (!p) {
+                log_syntax(unit, LOG_WARNING, filename, line, 0,
+                           "Failed to parse %s=%s'. Invalid format, ignoring.", lvalue, rvalue);
+                return 0;
+        }
+        return free_and_strdup(suboption_value, empty_to_null(p));
+}
+
 int config_parse_dhcp_server_relay_target(
                 const char *unit,
                 const char *filename,
index 9e5d24fbe8107200258897429a7251acd9b2ff73..7a1e3a51737f3a0ce008acb0d29b2f4eabef3d7e 100644 (file)
@@ -9,5 +9,6 @@ typedef struct Link Link;
 
 int dhcp4_server_configure(Link *link);
 
+CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_server_relay_agent_suboption);
 CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_server_relay_target);
 CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_server_emit);
index 902953a629c9cfdc34b796da9ca552e0963ef162..732b53f71dde1cf6e8bd4605f9b10d5d8b4926c8 100644 (file)
@@ -262,6 +262,8 @@ IPv6AcceptRA.PrefixDenyList,                 config_parse_ndisc_address_filter,
 IPv6AcceptRA.RouteAllowList,                 config_parse_ndisc_address_filter,                        0,                             offsetof(Network, ndisc_allow_listed_route_prefix)
 IPv6AcceptRA.RouteDenyList,                  config_parse_ndisc_address_filter,                        0,                             offsetof(Network, ndisc_deny_listed_route_prefix)
 DHCPServer.RelayTarget,                      config_parse_dhcp_server_relay_target,                    0,                             0
+DHCPServer.RelayAgentCircuitId,              config_parse_dhcp_server_relay_agent_suboption,           0,                             offsetof(Network, dhcp_server_relay_agent_circuit_id)
+DHCPServer.RelayAgentRemoteId,               config_parse_dhcp_server_relay_agent_suboption,           0,                             offsetof(Network, dhcp_server_relay_agent_remote_id)
 DHCPServer.MaxLeaseTimeSec,                  config_parse_sec,                                         0,                             offsetof(Network, dhcp_server_max_lease_time_usec)
 DHCPServer.DefaultLeaseTimeSec,              config_parse_sec,                                         0,                             offsetof(Network, dhcp_server_default_lease_time_usec)
 DHCPServer.EmitDNS,                          config_parse_bool,                                        0,                             offsetof(Network, dhcp_server_emit[SD_DHCP_LEASE_DNS].emit)
index 78a402625810b2f6541ec39c485df497cea6d29b..8b236342b50b2cc935021be26008682c0a442fc7 100644 (file)
@@ -548,6 +548,9 @@ static Network *network_free(Network *network) {
         net_match_clear(&network->match);
         condition_free_list(network->conditions);
 
+        free(network->dhcp_server_relay_agent_circuit_id);
+        free(network->dhcp_server_relay_agent_remote_id);
+
         free(network->description);
         free(network->dhcp_vendor_class_identifier);
         free(network->dhcp_mudurl);
index e8c2428becc29cada4d9f6091fab6ba2b2ff33d9..d7c216af6ee4e1f627f4cf961fa976a99ddd8c6e 100644 (file)
@@ -190,6 +190,9 @@ struct Network {
         bool dhcp_server;
         bool dhcp_server_bind_to_interface;
         struct in_addr dhcp_server_relay_target;
+        char *dhcp_server_relay_agent_circuit_id;
+        char *dhcp_server_relay_agent_remote_id;
+
         NetworkDHCPServerEmitAddress dhcp_server_emit[_SD_DHCP_LEASE_SERVER_TYPE_MAX];
         bool dhcp_server_emit_router;
         bool dhcp_server_emit_timezone;
index da0a5a7ac4771168a6f566e04fdbcbeedfae7610..0877a6b9a984693ada7f98e7a8e312993a05863a 100644 (file)
@@ -90,6 +90,7 @@ enum {
         SD_DHCP_OPTION_POP3_SERVER                 = 70,
         SD_DHCP_OPTION_USER_CLASS                  = 77,
         SD_DHCP_OPTION_FQDN                        = 81,
+        SD_DHCP_OPTION_RELAY_AGENT_INFORMATION     = 82,
         SD_DHCP_OPTION_NEW_POSIX_TIMEZONE          = 100,
         SD_DHCP_OPTION_NEW_TZDB_TIMEZONE           = 101,
         SD_DHCP_OPTION_DOMAIN_SEARCH_LIST          = 119,
@@ -105,6 +106,12 @@ enum {
         SD_DHCP_OPTION_END                         = 255,
 };
 
+/* Suboptions for SD_DHCP_OPTION_RELAY_AGENT_INFORMATION option */
+enum {
+        SD_DHCP_RELAY_AGENT_CIRCUIT_ID             = 1,
+        SD_DHCP_RELAY_AGENT_REMOTE_ID              = 2,
+};
+
 typedef struct sd_dhcp_client sd_dhcp_client;
 
 typedef int (*sd_dhcp_client_callback_t)(sd_dhcp_client *client, int event, void *userdata);
index 3cee2c2b062645879ee249aa43af10adeab93223..012d147ec13262c8f1365515873d4449da27d28f 100644 (file)
@@ -85,6 +85,8 @@ int sd_dhcp_server_forcerenew(sd_dhcp_server *server);
 
 int sd_dhcp_server_is_in_relay_mode(sd_dhcp_server *server);
 int sd_dhcp_server_set_relay_target(sd_dhcp_server *server, const struct in_addr* address);
+int sd_dhcp_server_set_relay_agent_information(sd_dhcp_server *server, const char* circuit_id, const char* remote_id);
+
 _SD_DEFINE_POINTER_CLEANUP_FUNC(sd_dhcp_server, sd_dhcp_server_unref);
 
 _SD_END_DECLARATIONS;
index 12d3e3cfcdf0f00ef4eb30326483ef6983f5bc13..127f26461e03687723545223fcfff67261ea383e 100644 (file)
@@ -362,6 +362,8 @@ SendOption=
 SendVendorOption=
 BindToInterface=
 RelayTarget=
+RelayAgentCircuitId=
+RelayAgentRemoteId=
 [NextHop]
 Id=
 Gateway=
index 0db83dc9d23a56764cd3f60d84f778007eb11e32..4142938056fcf22b5ea6b2b544b89477a189f6a1 100644 (file)
@@ -7,3 +7,5 @@ IPForward=ipv4
 [DHCPServer]
 RelayTarget=192.168.5.1
 BindToInterface=no
+RelayAgentCircuitId=string:sample_circuit_id
+RelayAgentRemoteId=string:sample_remote_id
index bf8add778bbbaf5da0ae4aaaee3e2dc5ac183eb2..1e50a75980a14c0025677f48da2172d6a14c5c31 100755 (executable)
@@ -3719,7 +3719,6 @@ class NetworkdDHCPServerRelayAgentTests(unittest.TestCase, Utilities):
         copy_unit_to_networkd_unit_path(*self.units)
         start_networkd()
 
-        #Test is disabled until BindToInterface DHCP server configuration option is supported
         self.wait_online(['client:routable'])
 
         output = check_output(*networkctl_cmd, '-n', '0', 'status', 'client', env=env)