1 /*
2 * Copyright (C) 2017-2026 Red Hat, Inc. All rights reserved.
3 *
4 * Author: Fabio M. Di Nitto <fabbione@kronosnet.org>
5 *
6 * This software licensed under LGPL-2.0+
7 */
8
9 #include "config.h"
10
11 #include <errno.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <sys/types.h>
15 #include <sys/stat.h>
16 #include <sys/wait.h>
17 #include <unistd.h>
18 #include <limits.h>
19 #include <stdio.h>
20 #include <stdint.h>
21 #include <netinet/in.h>
22 #include <arpa/inet.h>
23
24 #include "libnozzle.h"
25 #include "internals.h"
26
27 static int read_pipe(int fd, char **file, size_t *length)
28 {
29 char buf[4096];
30 int n;
31 int done = 0;
32
33 *file = NULL;
34 *length = 0;
35
36 memset(buf, 0, sizeof(buf));
37
|
(1) Event path: |
Condition "!done", taking true branch. |
|
(8) Event path: |
Condition "!done", taking true branch. |
|
(16) Event path: |
Condition "!done", taking true branch. |
|
(27) Event path: |
Condition "!done", taking false branch. |
38 while (!done) {
39
40 n = read(fd, buf, sizeof(buf));
41
|
(2) Event path: |
Condition "n < 0", taking false branch. |
|
(9) Event path: |
Condition "n < 0", taking false branch. |
|
(17) Event path: |
Condition "n < 0", taking false branch. |
42 if (n < 0) {
43 if (errno == EINTR)
44 continue;
45
46 if (*file)
47 free(*file);
48
49 return n;
50 }
51
|
(3) Event path: |
Condition "n == 0", taking false branch. |
|
(10) Event path: |
Condition "n == 0", taking false branch. |
|
(18) Event path: |
Condition "n == 0", taking true branch. |
|
(19) Event path: |
Condition "!*length", taking false branch. |
52 if (n == 0 && (!*length))
53 return 0;
54
|
(4) Event path: |
Condition "n == 0", taking false branch. |
|
(11) Event path: |
Condition "n == 0", taking false branch. |
|
(20) Event path: |
Condition "n == 0", taking true branch. |
55 if (n == 0)
56 done = 1;
57
|
(5) Event path: |
Condition "*file", taking false branch. |
|
(12) Event path: |
Condition "*file", taking true branch. |
|
(21) Event path: |
Condition "*file", taking true branch. |
58 if (*file)
|
(13) Event path: |
Falling through to end of if statement. |
|
(22) Event alloc_fn: |
Storage is returned from allocation function "realloc". |
|
(23) Event assign: |
Assigning: "*file" = "realloc(*file, *length + n + done)". |
|
(24) Event path: |
Falling through to end of if statement. |
59 *file = realloc(*file, (*length) + n + done);
60 else
61 *file = malloc(n + done);
62
|
(6) Event path: |
Condition "!*file", taking false branch. |
|
(14) Event path: |
Condition "!*file", taking false branch. |
|
(25) Event path: |
Condition "!*file", taking false branch. |
63 if (!*file)
64 return -1;
65
66 memmove((*file) + (*length), buf, n);
67 *length += (done + n);
|
(7) Event path: |
Jumping back to the beginning of the loop. |
|
(15) Event path: |
Jumping back to the beginning of the loop. |
|
(26) Event path: |
Jumping back to the beginning of the loop. |
68 }
69
70 /* Null terminator */
71 (*file)[(*length) - 1] = 0;
72
73 return 0;
74 }
75
76 int execute_bin_sh_command(const char *command, char **error_string)
77 {
78 pid_t pid;
79 int status, err = 0;
80 int fd[2];
81 size_t size = 0;
82
|
(1) Event path: |
Condition "command == NULL", taking false branch. |
|
(2) Event path: |
Condition "!error_string", taking false branch. |
83 if ((command == NULL) || (!error_string)) {
84 errno = EINVAL;
85 return -1;
86 }
87
88 *error_string = NULL;
89
90 err = pipe(fd);
|
(3) Event path: |
Condition "err", taking false branch. |
91 if (err)
92 goto out_clean;
93
94 pid = fork();
|
(4) Event path: |
Condition "pid < 0", taking false branch. |
95 if (pid < 0) {
96 err = pid;
97 goto out_clean;
98 }
99
|
(5) Event path: |
Condition "pid", taking true branch. |
100 if (pid) { /* parent */
101
102 close(fd[1]);
|
(6) Event alloc_arg: |
"read_pipe" allocates memory that is stored into "*error_string". [details] |
103 err = read_pipe(fd[0], error_string, &size);
|
(7) Event path: |
Condition "err", taking false branch. |
104 if (err)
105 goto out_clean0;
106
107 waitpid(pid, &status, 0);
|
(8) Event path: |
Condition "!((status & 0x7f) == 0)", taking true branch. |
108 if (!WIFEXITED(status)) {
109 err = -1;
|
(9) Event path: |
Jumping to label "out_clean0". |
110 goto out_clean0;
111 }
112 if (WIFEXITED(status) && WEXITSTATUS(status) != 0) {
113 err = WEXITSTATUS(status);
114 goto out_clean0;
115 }
116 goto out_clean0;
117 } else { /* child */
118 close(0);
119 close(1);
120 close(2);
121
122 close(fd[0]);
123 dup2(fd[1], 1);
124 dup2(fd[1], 2);
125 close(fd[1]);
126
127 execlp("/bin/sh", "/bin/sh", "-c", command, NULL);
128 exit(EXIT_FAILURE);
129 }
130
131 out_clean:
132 close(fd[1]);
133 out_clean0:
134 close(fd[0]);
135
136 return err;
137 }
138
139 char *generate_v4_broadcast(const char *ipaddr, const char *prefix)
140 {
141 int prefix_len;
142 struct in_addr mask;
143 struct in_addr broadcast;
144 struct in_addr address;
145 char buf[INET6_ADDRSTRLEN];
146
147 prefix_len = atoi(prefix);
148
149 if ((prefix_len > 32) || (prefix_len <= 0))
150 return NULL;
151
152 if (inet_pton(AF_INET, ipaddr, &address) <= 0)
153 return NULL;
154
155 mask.s_addr = htonl(~((1 << (32 - prefix_len)) - 1));
156
157 memset(&broadcast, 0, sizeof(broadcast));
158 broadcast.s_addr = (address.s_addr & mask.s_addr) | ~mask.s_addr;
159
160 return strdup(inet_ntop(AF_INET, (void *)&broadcast, buf, sizeof(buf)));
161 }
162
163 int _determine_family(const char *ipaddr)
164 {
165 if (!strchr(ipaddr, ':')) {
166 return AF_INET;
167 }
168 return AF_INET6;
169 }
170
171 int _validate_prefix(int family, const char *prefix)
172 {
173 int prefix_len;
174
175 prefix_len = atoi(prefix);
176
177 if (family == AF_INET) {
178 if (prefix_len <= 0 || prefix_len > 32) {
179 errno = EINVAL;
180 return -1;
181 }
182 } else {
183 if (prefix_len <= 0 || prefix_len > 128) {
184 errno = EINVAL;
185 return -1;
186 }
187 }
188
189 return prefix_len;
190 }
191
192 uint32_t _ipv4_prefix_to_netmask(int prefix_len)
193 {
194 return htonl(~((1 << (32 - prefix_len)) - 1));
195 }
196
197 void _ipv6_prefix_to_mask(int prefix_len, struct in6_addr *mask)
198 {
199 int i;
200
201 for (i = 0; i < (int)sizeof(struct in6_addr); i++) {
202 if (prefix_len >= 8) {
203 mask->s6_addr[i] = 0xff;
204 prefix_len -= 8;
205 } else if (prefix_len > 0) {
206 mask->s6_addr[i] = (0xff << (8 - prefix_len)) & 0xff;
207 prefix_len = 0;
208 } else {
209 mask->s6_addr[i] = 0;
210 }
211 }
212 }
213
214 int find_ip(nozzle_t nozzle,
215 const char *ipaddr, const char *prefix,
216 struct nozzle_ip **ip, struct nozzle_ip **ip_prev)
217 {
218 struct nozzle_ip *local_ip, *local_ip_prev;
219 int found = 0;
220
221 local_ip = local_ip_prev = nozzle->ip;
222
223 while(local_ip) {
224 if ((!strcmp(local_ip->ipaddr, ipaddr)) && (!strcmp(local_ip->prefix, prefix))) {
225 found = 1;
226 break;
227 }
228 local_ip_prev = local_ip;
229 local_ip = local_ip->next;
230 }
231
232 if (found) {
233 *ip = local_ip;
234 *ip_prev = local_ip_prev;
235 }
236
237 return found;
238 }
239