1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 
3 #include "bus-message-util.h"
4 
5 #include "resolve-util.h"
6 
bus_message_read_ifindex(sd_bus_message * message,sd_bus_error * error,int * ret)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_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index");
21 
22         *ret = ifindex;
23 
24         return 0;
25 }
26 
bus_message_read_family(sd_bus_message * message,sd_bus_error * error,int * ret)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 
bus_message_read_in_addr_auto(sd_bus_message * message,sd_bus_error * error,int * ret_family,union in_addr_union * ret_addr)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_set(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 
bus_message_read_dns_one(sd_bus_message * message,sd_bus_error * error,bool extended,int * ret_family,union in_addr_union * ret_address,uint16_t * ret_port,const char ** ret_server_name)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                 r = sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid DNS server address");
103                 assert(r < 0);
104                 return r;
105         }
106 
107         if (extended) {
108                 r = sd_bus_message_read(message, "q", &port);
109                 if (r < 0)
110                         return r;
111 
112                 if (IN_SET(port, 53, 853))
113                         port = 0;
114 
115                 r = sd_bus_message_read(message, "s", &server_name);
116                 if (r < 0)
117                         return r;
118         }
119 
120         r = sd_bus_message_exit_container(message);
121         if (r < 0)
122                 return r;
123 
124         *ret_family = family;
125         *ret_address = a;
126         *ret_port = port;
127         *ret_server_name = server_name;
128 
129         return 1;
130 }
131 
bus_message_read_dns_servers(sd_bus_message * message,sd_bus_error * error,bool extended,struct in_addr_full *** ret_dns,size_t * ret_n_dns)132 int bus_message_read_dns_servers(
133                         sd_bus_message *message,
134                         sd_bus_error *error,
135                         bool extended,
136                         struct in_addr_full ***ret_dns,
137                         size_t *ret_n_dns) {
138 
139         struct in_addr_full **dns = NULL;
140         size_t n = 0;
141         int r;
142 
143         assert(message);
144         assert(ret_dns);
145         assert(ret_n_dns);
146 
147         r = sd_bus_message_enter_container(message, 'a', extended ? "(iayqs)" : "(iay)");
148         if (r < 0)
149                 return r;
150 
151         for (;;) {
152                 const char *server_name;
153                 union in_addr_union a;
154                 uint16_t port;
155                 int family;
156 
157                 r = bus_message_read_dns_one(message, error, extended, &family, &a, &port, &server_name);
158                 if (r < 0)
159                         goto clear;
160                 if (r == 0)
161                         break;
162 
163                 if (!GREEDY_REALLOC(dns, n+1)) {
164                         r = -ENOMEM;
165                         goto clear;
166                 }
167 
168                 r = in_addr_full_new(family, &a, port, 0, server_name, dns + n);
169                 if (r < 0)
170                         goto clear;
171 
172                 n++;
173         }
174 
175         *ret_dns = TAKE_PTR(dns);
176         *ret_n_dns = n;
177         return 0;
178 
179 clear:
180         for (size_t i = 0; i < n; i++)
181                 in_addr_full_free(dns[i]);
182         free(dns);
183 
184         return r;
185 }
186