1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 
3 #include "condition.h"
4 #include "conf-parser.h"
5 #include "escape.h"
6 #include "networkd-link.h"
7 #include "networkd-util.h"
8 #include "parse-util.h"
9 #include "string-table.h"
10 #include "string-util.h"
11 #include "web-util.h"
12 
13 /* This is used in log messages, and never used in parsing settings. So, upper cases are OK. */
14 static const char * const network_config_source_table[_NETWORK_CONFIG_SOURCE_MAX] = {
15         [NETWORK_CONFIG_SOURCE_FOREIGN] = "foreign",
16         [NETWORK_CONFIG_SOURCE_STATIC]  = "static",
17         [NETWORK_CONFIG_SOURCE_IPV4LL]  = "IPv4LL",
18         [NETWORK_CONFIG_SOURCE_DHCP4]   = "DHCPv4",
19         [NETWORK_CONFIG_SOURCE_DHCP6]   = "DHCPv6",
20         [NETWORK_CONFIG_SOURCE_DHCP_PD] = "DHCP-PD",
21         [NETWORK_CONFIG_SOURCE_NDISC]   = "NDisc",
22         [NETWORK_CONFIG_SOURCE_RUNTIME] = "runtime",
23 };
24 
25 DEFINE_STRING_TABLE_LOOKUP_TO_STRING(network_config_source, NetworkConfigSource);
26 
network_config_state_to_string_alloc(NetworkConfigState s,char ** ret)27 int network_config_state_to_string_alloc(NetworkConfigState s, char **ret) {
28         static const char* states[] = {
29                 [LOG2U(NETWORK_CONFIG_STATE_PROBING)]     = "probing",
30                 [LOG2U(NETWORK_CONFIG_STATE_REQUESTING)]  = "requesting",
31                 [LOG2U(NETWORK_CONFIG_STATE_CONFIGURING)] = "configuring",
32                 [LOG2U(NETWORK_CONFIG_STATE_CONFIGURED)]  = "configured",
33                 [LOG2U(NETWORK_CONFIG_STATE_MARKED)]      = "marked",
34                 [LOG2U(NETWORK_CONFIG_STATE_REMOVING)]    = "removing",
35         };
36         _cleanup_free_ char *buf = NULL;
37 
38         assert(ret);
39 
40         for (size_t i = 0; i < ELEMENTSOF(states); i++)
41                 if (FLAGS_SET(s, 1 << i)) {
42                         assert(states[i]);
43 
44                         if (!strextend_with_separator(&buf, ",", states[i]))
45                                 return -ENOMEM;
46                 }
47 
48         *ret = TAKE_PTR(buf);
49         return 0;
50 }
51 
52 static const char * const address_family_table[_ADDRESS_FAMILY_MAX] = {
53         [ADDRESS_FAMILY_NO]   = "no",
54         [ADDRESS_FAMILY_YES]  = "yes",
55         [ADDRESS_FAMILY_IPV4] = "ipv4",
56         [ADDRESS_FAMILY_IPV6] = "ipv6",
57 };
58 
59 static const char * const routing_policy_rule_address_family_table[_ADDRESS_FAMILY_MAX] = {
60         [ADDRESS_FAMILY_YES]  = "both",
61         [ADDRESS_FAMILY_IPV4] = "ipv4",
62         [ADDRESS_FAMILY_IPV6] = "ipv6",
63 };
64 
65 static const char * const nexthop_address_family_table[_ADDRESS_FAMILY_MAX] = {
66         [ADDRESS_FAMILY_IPV4] = "ipv4",
67         [ADDRESS_FAMILY_IPV6] = "ipv6",
68 };
69 
70 static const char * const duplicate_address_detection_address_family_table[_ADDRESS_FAMILY_MAX] = {
71         [ADDRESS_FAMILY_NO]   = "none",
72         [ADDRESS_FAMILY_YES]  = "both",
73         [ADDRESS_FAMILY_IPV4] = "ipv4",
74         [ADDRESS_FAMILY_IPV6] = "ipv6",
75 };
76 
77 static const char * const dhcp_deprecated_address_family_table[_ADDRESS_FAMILY_MAX] = {
78         [ADDRESS_FAMILY_NO]   = "none",
79         [ADDRESS_FAMILY_YES]  = "both",
80         [ADDRESS_FAMILY_IPV4] = "v4",
81         [ADDRESS_FAMILY_IPV6] = "v6",
82 };
83 
84 static const char * const ip_masquerade_address_family_table[_ADDRESS_FAMILY_MAX] = {
85         [ADDRESS_FAMILY_NO]   = "no",
86         [ADDRESS_FAMILY_YES]  = "both",
87         [ADDRESS_FAMILY_IPV4] = "ipv4",
88         [ADDRESS_FAMILY_IPV6] = "ipv6",
89 };
90 
91 static const char * const dhcp_lease_server_type_table[_SD_DHCP_LEASE_SERVER_TYPE_MAX] = {
92         [SD_DHCP_LEASE_DNS]  = "DNS servers",
93         [SD_DHCP_LEASE_NTP]  = "NTP servers",
94         [SD_DHCP_LEASE_SIP]  = "SIP servers",
95         [SD_DHCP_LEASE_POP3] = "POP3 servers",
96         [SD_DHCP_LEASE_SMTP] = "SMTP servers",
97         [SD_DHCP_LEASE_LPR]  = "LPR servers",
98 };
99 
100 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(address_family, AddressFamily, ADDRESS_FAMILY_YES);
101 
link_local_address_family_from_string(const char * s)102 AddressFamily link_local_address_family_from_string(const char *s) {
103         if (streq_ptr(s, "fallback"))         /* compat name */
104                 return ADDRESS_FAMILY_YES;
105         if (streq_ptr(s, "fallback-ipv4"))    /* compat name */
106                 return ADDRESS_FAMILY_IPV4;
107         return address_family_from_string(s);
108 }
109 
110 DEFINE_STRING_TABLE_LOOKUP(routing_policy_rule_address_family, AddressFamily);
111 DEFINE_STRING_TABLE_LOOKUP(nexthop_address_family, AddressFamily);
112 DEFINE_STRING_TABLE_LOOKUP(duplicate_address_detection_address_family, AddressFamily);
113 DEFINE_CONFIG_PARSE_ENUM(config_parse_link_local_address_family, link_local_address_family,
114                          AddressFamily, "Failed to parse option");
115 DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_deprecated_address_family, AddressFamily);
116 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(ip_masquerade_address_family, AddressFamily);
117 DEFINE_STRING_TABLE_LOOKUP(dhcp_lease_server_type, sd_dhcp_lease_server_type_t);
118 
config_parse_address_family_with_kernel(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)119 int config_parse_address_family_with_kernel(
120                 const char* unit,
121                 const char *filename,
122                 unsigned line,
123                 const char *section,
124                 unsigned section_line,
125                 const char *lvalue,
126                 int ltype,
127                 const char *rvalue,
128                 void *data,
129                 void *userdata) {
130 
131         AddressFamily *fwd = data, s;
132 
133         assert(filename);
134         assert(lvalue);
135         assert(rvalue);
136         assert(data);
137 
138         /* This function is mostly obsolete now. It simply redirects
139          * "kernel" to "no". In older networkd versions we used to
140          * distinguish IPForward=off from IPForward=kernel, where the
141          * former would explicitly turn off forwarding while the
142          * latter would simply not touch the setting. But that logic
143          * is gone, hence silently accept the old setting, but turn it
144          * to "no". */
145 
146         s = address_family_from_string(rvalue);
147         if (s < 0) {
148                 if (streq(rvalue, "kernel"))
149                         s = ADDRESS_FAMILY_NO;
150                 else {
151                         log_syntax(unit, LOG_WARNING, filename, line, 0, "Failed to parse IPForward= option, ignoring: %s", rvalue);
152                         return 0;
153                 }
154         }
155 
156         *fwd = s;
157 
158         return 0;
159 }
160 
config_parse_ip_masquerade(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)161 int config_parse_ip_masquerade(
162                 const char *unit,
163                 const char *filename,
164                 unsigned line,
165                 const char *section,
166                 unsigned section_line,
167                 const char *lvalue,
168                 int ltype,
169                 const char *rvalue,
170                 void *data,
171                 void *userdata) {
172 
173         AddressFamily a, *ret = data;
174         int r;
175 
176         if (isempty(rvalue)) {
177                 *ret = ADDRESS_FAMILY_NO;
178                 return 0;
179         }
180 
181         r = parse_boolean(rvalue);
182         if (r >= 0) {
183                 if (r)
184                         log_syntax(unit, LOG_WARNING, filename, line, 0,
185                                    "IPMasquerade=%s is deprecated, and it is handled as \"ipv4\" instead of \"both\". "
186                                    "Please use \"ipv4\" or \"both\".",
187                                    rvalue);
188 
189                 *ret = r ? ADDRESS_FAMILY_IPV4 : ADDRESS_FAMILY_NO;
190                 return 0;
191         }
192 
193         a = ip_masquerade_address_family_from_string(rvalue);
194         if (a < 0) {
195                 log_syntax(unit, LOG_WARNING, filename, line, a,
196                            "Failed to parse IPMasquerade= setting, ignoring assignment: %s", rvalue);
197                 return 0;
198         }
199 
200         *ret = a;
201         return 0;
202 }
203 
config_parse_mud_url(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)204 int config_parse_mud_url(
205                 const char *unit,
206                 const char *filename,
207                 unsigned line,
208                 const char *section,
209                 unsigned section_line,
210                 const char *lvalue,
211                 int ltype,
212                 const char *rvalue,
213                 void *data,
214                 void *userdata) {
215 
216         _cleanup_free_ char *unescaped = NULL;
217         char **url = data;
218         ssize_t l;
219 
220         assert(filename);
221         assert(lvalue);
222         assert(rvalue);
223         assert(url);
224 
225         if (isempty(rvalue)) {
226                 *url = mfree(*url);
227                 return 0;
228         }
229 
230         l = cunescape(rvalue, 0, &unescaped);
231         if (l < 0) {
232                 log_syntax(unit, LOG_WARNING, filename, line, l,
233                            "Failed to unescape MUD URL, ignoring: %s", rvalue);
234                 return 0;
235         }
236 
237         if (l > UINT8_MAX || !http_url_is_valid(unescaped)) {
238                 log_syntax(unit, LOG_WARNING, filename, line, 0,
239                            "Invalid MUD URL, ignoring: %s", rvalue);
240                 return 0;
241         }
242 
243         return free_and_replace(*url, unescaped);
244 }
245 
log_link_message_full_errno(Link * link,sd_netlink_message * m,int level,int err,const char * msg)246 int log_link_message_full_errno(Link *link, sd_netlink_message *m, int level, int err, const char *msg) {
247         const char *err_msg = NULL;
248 
249         /* link may be NULL. */
250 
251         (void) sd_netlink_message_read_string(m, NLMSGERR_ATTR_MSG, &err_msg);
252         return log_link_full_errno(link, level, err,
253                                    "%s: %s%s%s%m",
254                                    msg,
255                                    strempty(err_msg),
256                                    err_msg && !endswith(err_msg, ".") ? "." : "",
257                                    err_msg ? " " : "");
258 }
259