1. DHCP server trasmit
2. Client parses and saves in leases
Implements http://www.rfc-editor.org/rfc/rfc3361.txt
```
Frame 134: 348 bytes on wire (2784 bits), 348 bytes captured (2784 bits) on interface 0
Ethernet II, Src: 42:65:85:d6:4e:32 (42:65:85:d6:4e:32), Dst: 1e:04:f8:b8:2f:d4 (1e:04:f8:b8:2f:d4)
Internet Protocol Version 4, Src: 192.168.5.1, Dst: 192.168.5.11
User Datagram Protocol, Src Port: 67, Dst Port: 68
Dynamic Host Configuration Protocol (ACK)
Message type: Boot Reply (2)
Hardware type: Ethernet (0x01)
Hardware address length: 6
Hops: 0
Transaction ID: 0x7cc87cb4
Seconds elapsed: 0
Bootp flags: 0x0000 (Unicast)
Client IP address: 0.0.0.0
Your (client) IP address: 192.168.5.11
Next server IP address: 0.0.0.0
Relay agent IP address: 0.0.0.0
Client MAC address: 1e:04:f8:b8:2f:d4 (1e:04:f8:b8:2f:d4)
Client hardware address padding:
00000000000000000000
Server host name not given
Boot file name not given
Magic cookie: DHCP
Option: (53) DHCP Message Type (ACK)
Length: 1
DHCP: ACK (5)
Option: (51) IP Address Lease Time
Length: 4
IP Address Lease Time: (3600s) 1 hour
Option: (1) Subnet Mask (255.255.255.0)
Length: 4
Subnet Mask: 255.255.255.0
Option: (3) Router
Length: 4
Router: 192.168.5.1
Option: (6) Domain Name Server
Length: 4
Domain Name Server: 192.168.5.1
Option: (42) Network Time Protocol Servers
Length: 4
Network Time Protocol Server: 192.168.1.1
Option: (120) SIP Servers <=====here
Length: 9
SIP Server Encoding: IPv4 Address (1)
SIP Server Address: 192.168.1.1
SIP Server Address: 192.168.5.2
Option: (101) TCode
Length: 13
TZ TCode: Europe/Berlin
Option: (54) DHCP Server Identifier (192.168.5.1)
Length: 4
DHCP Server Identifier: 192.168.5.1
Option: (255) End
Option End: 255
```
```
cat /run/systemd/netif/state ✔ ⚡ 3148 16:40:51
OPER_STATE=routable
CARRIER_STATE=carrier
ADDRESS_STATE=routable
DNS=192.168.94.2 192.168.5.1
NTP=192.168.5.1
SIP=192.168.1.1 192.168.5.2
```
aa
</listitem>
</varlistentry>
<varlistentry>
+ <term><varname>UseSIP=</varname></term>
+ <listitem>
+ <para>When true (the default), the SIP servers received
+ from the DHCP server will be saved at the state files and can be
+ read via <function>sd_network_link_get_sip_servers()</function> function.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
<term><varname>UseMTU=</varname></term>
<listitem>
<para>When true, the interface maximum transmission unit
</varlistentry>
<varlistentry>
+ <term><varname>EmitSIP=</varname></term>
+ <term><varname>SIP=</varname></term>
+
+ <listitem><para>Similar to the <varname>EmitDNS=</varname> and
+ <varname>DNS=</varname> settings described above, these
+ settings configure whether and what SIP server information
+ shall be emitted as part of the DHCP lease. The same syntax,
+ propagation semantics and defaults apply as for
+ <varname>EmitDNS=</varname> and
+ <varname>DNS=</varname>.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><varname>EmitRouter=</varname></term>
<listitem><para>Similar to the <varname>EmitDNS=</varname>
struct in_addr *ntp;
size_t ntp_size;
+ struct in_addr *sip;
+ size_t sip_size;
+
struct sd_dhcp_route *static_route;
size_t static_route_size, static_route_allocated;
break;
}
+ case SD_DHCP_OPTION_SIP_SERVER:
+ if (*offset + 3 + optlen > size)
+ return -ENOBUFS;
+
+ options[*offset] = code;
+ options[*offset + 1] = optlen + 1;
+ options[*offset + 2] = 1;
+
+ memcpy_safe(&options[*offset + 3], optval, optlen);
+ *offset += 3 + optlen;
+
+ break;
default:
if (*offset + 2 + optlen > size)
return -ENOBUFS;
char *timezone;
- struct in_addr *ntp, *dns;
- unsigned n_ntp, n_dns;
+ struct in_addr *ntp, *dns, *sip;
+ unsigned n_ntp, n_dns, n_sip;
bool emit_router;
return (int) lease->ntp_size;
}
+int sd_dhcp_lease_get_sip(sd_dhcp_lease *lease, const struct in_addr **addr) {
+ assert_return(lease, -EINVAL);
+ assert_return(addr, -EINVAL);
+
+ if (lease->sip_size <= 0)
+ return -ENODATA;
+
+ *addr = lease->sip;
+ return (int) lease->sip_size;
+}
+
int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname) {
assert_return(lease, -EINVAL);
assert_return(domainname, -EINVAL);
free(lease->domainname);
free(lease->dns);
free(lease->ntp);
+ free(lease->sip);
free(lease->static_route);
free(lease->client_id);
free(lease->vendor_specific);
return 0;
}
+static int lease_parse_sip_server(const uint8_t *option, size_t len, struct in_addr **ret, size_t *n_ret) {
+ assert(option);
+ assert(ret);
+ assert(n_ret);
+
+ if (len <= 0) {
+ *ret = mfree(*ret);
+ *n_ret = 0;
+ } else {
+ size_t n_addresses;
+ struct in_addr *addresses;
+ int l = len - 1;
+
+ if (l % 4 != 0)
+ return -EINVAL;
+
+ n_addresses = l / 4;
+
+ addresses = newdup(struct in_addr, option + 1, n_addresses);
+ if (!addresses)
+ return -ENOMEM;
+
+ free(*ret);
+ *ret = addresses;
+ *n_ret = n_addresses;
+ }
+
+ return 0;
+}
+
static int lease_parse_routes(
const uint8_t *option, size_t len,
struct sd_dhcp_route **routes, size_t *routes_size, size_t *routes_allocated) {
log_debug_errno(r, "Failed to parse NTP server, ignoring: %m");
break;
+ case SD_DHCP_OPTION_SIP_SERVER:
+ r = lease_parse_sip_server(option, len, &lease->sip, &lease->sip_size);
+ if (r < 0)
+ log_debug_errno(r, "Failed to parse SIP server, ignoring: %m");
+ break;
+
case SD_DHCP_OPTION_STATIC_ROUTE:
r = lease_parse_routes(option, len, &lease->static_route, &lease->static_route_size, &lease->static_route_allocated);
if (r < 0)
fputc('\n', f);
}
+ r = sd_dhcp_lease_get_sip(lease, &addresses);
+ if (r > 0) {
+ fputs("SIP=", f);
+ serialize_in_addrs(f, addresses, r, false, NULL);
+ fputc('\n', f);
+ }
+
r = sd_dhcp_lease_get_domainname(lease, &string);
if (r >= 0)
fprintf(f, "DOMAINNAME=%s\n", string);
*broadcast = NULL,
*dns = NULL,
*ntp = NULL,
+ *sip = NULL,
*mtu = NULL,
*routes = NULL,
*domains = NULL,
"BROADCAST", &broadcast,
"DNS", &dns,
"NTP", &ntp,
+ "SIP", &sip,
"MTU", &mtu,
"DOMAINNAME", &lease->domainname,
"HOSTNAME", &lease->hostname,
lease->ntp_size = r;
}
+ if (sip) {
+ r = deserialize_in_addrs(&lease->sip, sip);
+ if (r < 0)
+ log_debug_errno(r, "Failed to deserialize SIP servers %s, ignoring: %m", ntp);
+ else
+ lease->ntp_size = r;
+ }
+
if (mtu) {
r = safe_atou16(mtu, &lease->mtu);
if (r < 0)
free(server->timezone);
free(server->dns);
free(server->ntp);
+ free(server->sip);
hashmap_free(server->leases_by_client_id);
return r;
}
+ if (server->n_sip > 0) {
+ r = dhcp_option_append(
+ &packet->dhcp, req->max_optlen, &offset, 0,
+ SD_DHCP_OPTION_SIP_SERVER,
+ sizeof(struct in_addr) * server->n_sip, server->sip);
+ if (r < 0)
+ return r;
+ }
+
if (server->timezone) {
r = dhcp_option_append(
&packet->dhcp, req->max_optlen, &offset, 0,
return 1;
}
+int sd_dhcp_server_set_sip(sd_dhcp_server *server, const struct in_addr sip[], unsigned n) {
+ assert_return(server, -EINVAL);
+ assert_return(sip || n <= 0, -EINVAL);
+
+ if (server->n_sip == n &&
+ memcmp(server->sip, sip, sizeof(struct in_addr) * n) == 0)
+ return 0;
+
+ if (n <= 0) {
+ server->sip = mfree(server->sip);
+ server->n_sip = 0;
+ } else {
+ struct in_addr *c;
+
+ c = newdup(struct in_addr, sip, n);
+ if (!c)
+ return -ENOMEM;
+
+ free(server->sip);
+ server->sip = c;
+ server->n_sip = n;
+ }
+
+ return 1;
+}
+
int sd_dhcp_server_set_emit_router(sd_dhcp_server *server, int enabled) {
assert_return(server, -EINVAL);
return network_link_get_strv(ifindex, "ROUTE_DOMAINS", ret);
}
+_public_ int sd_network_link_get_sip_servers(int ifindex, char ***ret) {
+ return network_link_get_strv(ifindex, "SIP", ret);
+}
+
_public_ int sd_network_link_get_dns_default_route(int ifindex) {
char path[STRLEN("/run/systemd/netif/links/") + DECIMAL_STR_MAX(ifindex) + 1];
_cleanup_free_ char *s = NULL;
return 0;
}
+int config_parse_dhcp_use_sip(
+ 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) {
+
+ Network *network = data;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ r = parse_boolean(rvalue);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r,
+ "Failed to parse UseSIP=%s, ignoring assignment: %m", rvalue);
+ return 0;
+ }
+
+ network->dhcp_use_sip = r;
+
+ return 0;
+}
+
int config_parse_dhcp_use_ntp(
const char* unit,
const char *filename,
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_use_dns);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_use_domains);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_use_ntp);
+CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_use_sip);
CONFIG_PARSER_PROTOTYPE(config_parse_iaid);
CONFIG_PARSER_PROTOTYPE(config_parse_section_route_table);
return sd_dhcp_server_set_ntp(s, addresses, n_addresses);
}
+static int link_push_uplink_sip_to_dhcp_server(Link *link, sd_dhcp_server *s) {
+ _cleanup_free_ struct in_addr *addresses = NULL;
+ size_t n_addresses = 0, n_allocated = 0;
+ char **a;
+
+ if (!link->network)
+ return 0;
+
+ log_debug("Copying SIP server information from %s", link->ifname);
+
+ STRV_FOREACH(a, link->network->sip) {
+ union in_addr_union ia;
+
+ /* Only look for IPv4 addresses */
+ if (in_addr_from_string(AF_INET, *a, &ia) <= 0)
+ continue;
+
+ /* Never propagate obviously borked data */
+ if (in4_addr_is_null(&ia.in) || in4_addr_is_localhost(&ia.in))
+ continue;
+
+ if (!GREEDY_REALLOC(addresses, n_allocated, n_addresses + 1))
+ return log_oom();
+
+ addresses[n_addresses++] = ia.in;
+ }
+
+ if (link->network->dhcp_use_sip && link->dhcp_lease) {
+ const struct in_addr *da = NULL;
+ int j, n;
+
+ n = sd_dhcp_lease_get_sip(link->dhcp_lease, &da);
+ if (n > 0) {
+
+ if (!GREEDY_REALLOC(addresses, n_allocated, n_addresses + n))
+ return log_oom();
+
+ for (j = 0; j < n; j++)
+ if (in4_addr_is_non_local(&da[j]))
+ addresses[n_addresses++] = da[j];
+ }
+ }
+
+ if (n_addresses <= 0)
+ return 0;
+
+ return sd_dhcp_server_set_sip(s, addresses, n_addresses);
+}
+
int dhcp4_server_configure(Link *link) {
Address *address;
Link *uplink = NULL;
log_link_warning_errno(link, r, "Failed to set NTP server for DHCP server, ignoring: %m");
}
+ if (link->network->dhcp_server_emit_sip) {
+ if (link->network->n_dhcp_server_sip > 0)
+ r = sd_dhcp_server_set_sip(link->dhcp_server, link->network->dhcp_server_sip, link->network->n_dhcp_server_sip);
+ else {
+ if (!acquired_uplink)
+ uplink = manager_find_uplink(link->manager, link);
+
+ if (!uplink) {
+ log_link_debug(link, "Not emitting sip server information on link, couldn't find suitable uplink.");
+ r = 0;
+ } else
+ r = link_push_uplink_sip_to_dhcp_server(uplink, link->dhcp_server);
+
+ }
+ if (r < 0)
+ log_link_warning_errno(link, r, "Failed to set SIP server for DHCP server, ignoring: %m");
+ }
+
r = sd_dhcp_server_set_emit_router(link->dhcp_server, link->network->dhcp_server_emit_router);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to set router emission for DHCP server: %m");
n->dhcp_server_ntp = m;
}
}
+
+int config_parse_dhcp_server_sip(
+ 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) {
+
+ Network *n = data;
+ const char *p = rvalue;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+
+ for (;;) {
+ _cleanup_free_ char *w = NULL;
+ union in_addr_union a;
+ struct in_addr *m;
+
+ r = extract_first_word(&p, &w, NULL, 0);
+ if (r == -ENOMEM)
+ return log_oom();
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r,
+ "Failed to extract word, ignoring: %s", rvalue);
+ return 0;
+ }
+ if (r == 0)
+ return 0;
+
+ r = in_addr_from_string(AF_INET, w, &a);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r,
+ "Failed to parse SIP server address '%s', ignoring: %m", w);
+ continue;
+ }
+
+ m = reallocarray(n->dhcp_server_sip, n->n_dhcp_server_sip + 1, sizeof(struct in_addr));
+ if (!m)
+ return log_oom();
+
+ m[n->n_dhcp_server_sip++] = a.in;
+ n->dhcp_server_sip = m;
+ }
+}
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_server_dns);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_server_ntp);
+CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_server_sip);
return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for NTP server: %m");
}
+ if (link->network->dhcp_use_sip) {
+ r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_SIP_SERVER);
+ if (r < 0)
+ return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for SIP server: %m");
+ }
+
if (link->network->dhcp_use_timezone) {
r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_NEW_TZDB_TIMEZONE);
if (r < 0)
space = true;
}
+ fputc('\n', f);
+
+ fputs("SIP=", f);
+ space = false;
+ fputstrv(f, link->network->sip, NULL, &space);
+
+ if (link->network->dhcp_use_sip &&
+ link->dhcp_lease) {
+ const struct in_addr *addresses;
+
+ r = sd_dhcp_lease_get_sip(link->dhcp_lease, &addresses);
+ if (r > 0)
+ if (serialize_in_addrs(f, addresses, r, space, in4_addr_is_non_local) > 0)
+ space = true;
+ }
+
if (link->network->dhcp6_use_ntp && dhcp6_lease) {
struct in6_addr *in6_addrs;
char **hosts;
}
static int manager_save(Manager *m) {
- _cleanup_ordered_set_free_free_ OrderedSet *dns = NULL, *ntp = NULL, *search_domains = NULL, *route_domains = NULL;
- Link *link;
- Iterator i;
- _cleanup_free_ char *temp_path = NULL;
- _cleanup_strv_free_ char **p = NULL;
- _cleanup_fclose_ FILE *f = NULL;
+ _cleanup_ordered_set_free_free_ OrderedSet *dns = NULL, *ntp = NULL, *sip = NULL, *search_domains = NULL, *route_domains = NULL;
+ const char *operstate_str, *carrier_state_str, *address_state_str;
LinkOperationalState operstate = LINK_OPERSTATE_OFF;
LinkCarrierState carrier_state = LINK_CARRIER_STATE_OFF;
LinkAddressState address_state = LINK_ADDRESS_STATE_OFF;
- const char *operstate_str, *carrier_state_str, *address_state_str;
+ _cleanup_free_ char *temp_path = NULL;
+ _cleanup_strv_free_ char **p = NULL;
+ _cleanup_fclose_ FILE *f = NULL;
+ Link *link;
+ Iterator i;
int r;
assert(m);
if (!ntp)
return -ENOMEM;
+ sip = ordered_set_new(&string_hash_ops);
+ if (!sip)
+ return -ENOMEM;
+
search_domains = ordered_set_new(&dns_name_hash_ops);
if (!search_domains)
return -ENOMEM;
return r;
}
+ if (link->network->dhcp_use_sip) {
+ const struct in_addr *addresses;
+
+ r = sd_dhcp_lease_get_sip(link->dhcp_lease, &addresses);
+ if (r > 0) {
+ r = ordered_set_put_in4_addrv(sip, addresses, r, in4_addr_is_non_local);
+ if (r < 0)
+ return r;
+ } else if (r < 0 && r != -ENODATA)
+ return r;
+ }
+
if (link->network->dhcp_use_domains != DHCP_USE_DOMAINS_NO) {
const char *domainname;
char **domains = NULL;
ordered_set_print(f, "DNS=", dns);
ordered_set_print(f, "NTP=", ntp);
+ ordered_set_print(f, "SIP=", sip);
ordered_set_print(f, "DOMAINS=", search_domains);
ordered_set_print(f, "ROUTE_DOMAINS=", route_domains);
DHCPv4.UseDNS, config_parse_bool, 0, offsetof(Network, dhcp_use_dns)
DHCPv4.RoutesToDNS, config_parse_bool, 0, offsetof(Network, dhcp_routes_to_dns)
DHCPv4.UseNTP, config_parse_bool, 0, offsetof(Network, dhcp_use_ntp)
+DHCPv4.UseSIP, config_parse_bool, 0, offsetof(Network, dhcp_use_sip)
DHCPv4.UseMTU, config_parse_bool, 0, offsetof(Network, dhcp_use_mtu)
DHCPv4.UseHostname, config_parse_bool, 0, offsetof(Network, dhcp_use_hostname)
DHCPv4.UseDomains, config_parse_dhcp_use_domains, 0, offsetof(Network, dhcp_use_domains)
DHCPServer.DNS, config_parse_dhcp_server_dns, 0, 0
DHCPServer.EmitNTP, config_parse_bool, 0, offsetof(Network, dhcp_server_emit_ntp)
DHCPServer.NTP, config_parse_dhcp_server_ntp, 0, 0
+DHCPServer.EmitSIP, config_parse_bool, 0, offsetof(Network, dhcp_server_emit_sip)
+DHCPServer.SIP, config_parse_dhcp_server_sip, 0, 0
DHCPServer.EmitRouter, config_parse_bool, 0, offsetof(Network, dhcp_server_emit_router)
DHCPServer.EmitTimezone, config_parse_bool, 0, offsetof(Network, dhcp_server_emit_timezone)
DHCPServer.Timezone, config_parse_timezone, 0, offsetof(Network, dhcp_server_timezone)
.dhcp = ADDRESS_FAMILY_NO,
.dhcp_critical = -1,
.dhcp_use_ntp = true,
+ .dhcp_use_sip = true,
.dhcp_use_dns = true,
.dhcp_use_hostname = true,
.dhcp_use_routes = true,
.dhcp_server_emit_dns = true,
.dhcp_server_emit_ntp = true,
+ .dhcp_server_emit_sip = true,
.dhcp_server_emit_router = true,
.dhcp_server_emit_timezone = true,
strv_free(network->ntp);
free(network->dns);
+ strv_free(network->sip);
+ free(network->sip);
ordered_set_free_free(network->search_domains);
ordered_set_free_free(network->route_domains);
strv_free(network->bind_carrier);
free(network->dhcp_server_timezone);
free(network->dhcp_server_dns);
free(network->dhcp_server_ntp);
+ free(network->dhcp_server_sip);
set_free_free(network->dnssec_negative_trust_anchors);
bool dhcp_use_dns;
bool dhcp_routes_to_dns;
bool dhcp_use_ntp;
+ bool dhcp_use_sip;
bool dhcp_use_mtu;
bool dhcp_use_routes;
bool dhcp_use_timezone;
/* DHCP Server Support */
bool dhcp_server;
+
bool dhcp_server_emit_dns;
struct in_addr *dhcp_server_dns;
unsigned n_dhcp_server_dns;
+
bool dhcp_server_emit_ntp;
struct in_addr *dhcp_server_ntp;
unsigned n_dhcp_server_ntp;
+
+ bool dhcp_server_emit_sip;
+ struct in_addr *dhcp_server_sip;
+ unsigned n_dhcp_server_sip;
+
bool dhcp_server_emit_router;
bool dhcp_server_emit_timezone;
char *dhcp_server_timezone;
Set *dnssec_negative_trust_anchors;
char **ntp;
+ char **sip;
char **bind_carrier;
};
SD_DHCP_OPTION_NEW_POSIX_TIMEZONE = 100,
SD_DHCP_OPTION_NEW_TZDB_TIMEZONE = 101,
SD_DHCP_OPTION_DOMAIN_SEARCH_LIST = 119,
+ SD_DHCP_OPTION_SIP_SERVER = 120,
SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE = 121,
SD_DHCP_OPTION_PRIVATE_BASE = 224,
/* Windows 10 option to send when Anonymize=true */
int sd_dhcp_lease_get_server_identifier(sd_dhcp_lease *lease, struct in_addr *addr);
int sd_dhcp_lease_get_dns(sd_dhcp_lease *lease, const struct in_addr **addr);
int sd_dhcp_lease_get_ntp(sd_dhcp_lease *lease, const struct in_addr **addr);
+int sd_dhcp_lease_get_sip(sd_dhcp_lease *lease, const struct in_addr **addr);
int sd_dhcp_lease_get_mtu(sd_dhcp_lease *lease, uint16_t *mtu);
int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname);
int sd_dhcp_lease_get_search_domains(sd_dhcp_lease *lease, char ***domains);
int sd_dhcp_server_configure_pool(sd_dhcp_server *server, struct in_addr *address, unsigned char prefixlen, uint32_t offset, uint32_t size);
int sd_dhcp_server_set_timezone(sd_dhcp_server *server, const char *timezone);
-int sd_dhcp_server_set_dns(sd_dhcp_server *server, const struct in_addr ntp[], unsigned n);
-int sd_dhcp_server_set_ntp(sd_dhcp_server *server, const struct in_addr dns[], unsigned n);
+int sd_dhcp_server_set_dns(sd_dhcp_server *server, const struct in_addr dns[], unsigned n);
+int sd_dhcp_server_set_ntp(sd_dhcp_server *server, const struct in_addr ntp[], unsigned n);
+int sd_dhcp_server_set_sip(sd_dhcp_server *server, const struct in_addr sip[], unsigned n);
int sd_dhcp_server_set_emit_router(sd_dhcp_server *server, int enabled);
int sd_dhcp_server_set_max_lease_time(sd_dhcp_server *server, uint32_t t);
/* Get the route DNS domain names for a given link. */
int sd_network_link_get_route_domains(int ifindex, char ***domains);
+/* Get the sip servers for a given link. */
+int sd_network_link_get_sip_servers(int ifindex, char ***sip);
+
/* Get whether this link shall be used as 'default route' for DNS queries */
int sd_network_link_get_dns_default_route(int ifindex);
IAID=
UserClass=
UseNTP=
+UseSIP=
UseMTU=
UseDomainName=
RouteMetric=
Timezone=
EmitDNS=
NTP=
+EmitSIP=
+SIP=
EmitRouter=
MaxLeaseTimeSec=
DefaultLeaseTimeSec=