mirror of
https://github.com/systemd/systemd-stable.git
synced 2024-12-22 13:33:56 +03:00
rfc3046 implementation
This commit is contained in:
parent
ebf940e1e9
commit
11c38d3e51
@ -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>
|
||||
|
||||
|
@ -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);
|
||||
|
@ -14,12 +14,33 @@
|
||||
#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,34 +114,93 @@ 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, ¤t_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, ¤t_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;
|
||||
|
||||
options[*offset] = code;
|
||||
options[*offset + 1] = optlen;
|
||||
|
||||
memcpy_safe(&options[*offset + 2], optval, optlen);
|
||||
*offset += 2 + optlen;
|
||||
|
||||
break;
|
||||
return dhcp_option_append_tlv(options, size, offset, code, optlen, optval);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int option_length(uint8_t *options, size_t length, size_t offset) {
|
||||
assert(options);
|
||||
assert(offset < length);
|
||||
|
||||
if (IN_SET(options[offset], SD_DHCP_OPTION_PAD, SD_DHCP_OPTION_END))
|
||||
return 1;
|
||||
if (length < offset + 2)
|
||||
return -ENOBUFS;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
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,
|
||||
uint8_t overload,
|
||||
uint8_t code, size_t optlen, const void *optval) {
|
||||
|
@ -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,
|
||||
|
@ -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_addr* address) {
|
||||
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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -362,6 +362,8 @@ SendOption=
|
||||
SendVendorOption=
|
||||
BindToInterface=
|
||||
RelayTarget=
|
||||
RelayAgentCircuitId=
|
||||
RelayAgentRemoteId=
|
||||
[NextHop]
|
||||
Id=
|
||||
Gateway=
|
||||
|
@ -7,3 +7,5 @@ IPForward=ipv4
|
||||
[DHCPServer]
|
||||
RelayTarget=192.168.5.1
|
||||
BindToInterface=no
|
||||
RelayAgentCircuitId=string:sample_circuit_id
|
||||
RelayAgentRemoteId=string:sample_remote_id
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user