]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/bus-message-util.c
license: LGPL-2.1+ -> LGPL-2.1-or-later
[thirdparty/systemd.git] / src / shared / bus-message-util.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include "bus-message-util.h"
4
5 #include "resolve-util.h"
6
7 int bus_message_read_ifindex(sd_bus_message *message, sd_bus_error *error, int *ret) {
8 int ifindex, r;
9
10 assert(message);
11 assert(ret);
12
13 assert_cc(sizeof(int) == sizeof(int32_t));
14
15 r = sd_bus_message_read(message, "i", &ifindex);
16 if (r < 0)
17 return r;
18
19 if (ifindex <= 0)
20 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index");
21
22 *ret = ifindex;
23
24 return 0;
25 }
26
27 int bus_message_read_family(sd_bus_message *message, sd_bus_error *error, int *ret) {
28 int family, r;
29
30 assert(message);
31 assert(ret);
32
33 assert_cc(sizeof(int) == sizeof(int32_t));
34
35 r = sd_bus_message_read(message, "i", &family);
36 if (r < 0)
37 return r;
38
39 if (!IN_SET(family, AF_INET, AF_INET6))
40 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family);
41
42 *ret = family;
43 return 0;
44 }
45
46 int bus_message_read_in_addr_auto(sd_bus_message *message, sd_bus_error *error, int *ret_family, union in_addr_union *ret_addr) {
47 int family, r;
48 const void *d;
49 size_t sz;
50
51 assert(message);
52
53 r = sd_bus_message_read(message, "i", &family);
54 if (r < 0)
55 return r;
56
57 r = sd_bus_message_read_array(message, 'y', &d, &sz);
58 if (r < 0)
59 return r;
60
61 if (!IN_SET(family, AF_INET, AF_INET6))
62 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family);
63
64 if (sz != FAMILY_ADDRESS_SIZE(family))
65 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid address size");
66
67 if (ret_family)
68 *ret_family = family;
69 if (ret_addr)
70 memcpy(ret_addr, d, sz);
71 return 0;
72 }
73
74 static int bus_message_read_dns_one(
75 sd_bus_message *message,
76 sd_bus_error *error,
77 bool extended,
78 int *ret_family,
79 union in_addr_union *ret_address,
80 uint16_t *ret_port,
81 const char **ret_server_name) {
82 const char *server_name = NULL;
83 union in_addr_union a;
84 uint16_t port = 0;
85 int family, r;
86
87 assert(message);
88 assert(ret_family);
89 assert(ret_address);
90 assert(ret_port);
91 assert(ret_server_name);
92
93 r = sd_bus_message_enter_container(message, 'r', extended ? "iayqs" : "iay");
94 if (r <= 0)
95 return r;
96
97 r = bus_message_read_in_addr_auto(message, error, &family, &a);
98 if (r < 0)
99 return r;
100
101 if (!dns_server_address_valid(family, &a))
102 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid DNS server address");
103
104 if (extended) {
105 r = sd_bus_message_read(message, "q", &port);
106 if (r < 0)
107 return r;
108
109 if (IN_SET(port, 53, 853))
110 port = 0;
111
112 r = sd_bus_message_read(message, "s", &server_name);
113 if (r < 0)
114 return r;
115 }
116
117 r = sd_bus_message_exit_container(message);
118 if (r < 0)
119 return r;
120
121 *ret_family = family;
122 *ret_address = a;
123 *ret_port = port;
124 *ret_server_name = server_name;
125
126 return 1;
127 }
128
129 int bus_message_read_dns_servers(
130 sd_bus_message *message,
131 sd_bus_error *error,
132 bool extended,
133 struct in_addr_full ***ret_dns,
134 size_t *ret_n_dns) {
135
136 struct in_addr_full **dns = NULL;
137 size_t n = 0, allocated = 0;
138 int r;
139
140 assert(message);
141 assert(ret_dns);
142 assert(ret_n_dns);
143
144 r = sd_bus_message_enter_container(message, 'a', extended ? "(iayqs)" : "(iay)");
145 if (r < 0)
146 return r;
147
148 for (;;) {
149 const char *server_name;
150 union in_addr_union a;
151 uint16_t port;
152 int family;
153
154 r = bus_message_read_dns_one(message, error, extended, &family, &a, &port, &server_name);
155 if (r < 0)
156 goto clear;
157 if (r == 0)
158 break;
159
160 if (!GREEDY_REALLOC(dns, allocated, n+1)) {
161 r = -ENOMEM;
162 goto clear;
163 }
164
165 r = in_addr_full_new(family, &a, port, 0, server_name, dns + n);
166 if (r < 0)
167 goto clear;
168
169 n++;
170 }
171
172 *ret_dns = TAKE_PTR(dns);
173 *ret_n_dns = n;
174 return 0;
175
176 clear:
177 for (size_t i = 0; i < n; i++)
178 in_addr_full_free(dns[i]);
179 free(dns);
180
181 return r;
182 }