]>
Commit | Line | Data |
---|---|---|
acddc0ed | 1 | // SPDX-License-Identifier: ISC |
8429abe0 RW |
2 | /* $OpenBSD$ */ |
3 | ||
4 | /* | |
5 | * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> | |
8429abe0 RW |
6 | */ |
7 | ||
eac6e3f0 | 8 | #include <zebra.h> |
8429abe0 | 9 | #include <sys/un.h> |
8429abe0 RW |
10 | |
11 | #include "ldpd.h" | |
12 | #include "ldpe.h" | |
13 | #include "log.h" | |
14 | #include "control.h" | |
15 | ||
16 | #define CONTROL_BACKLOG 5 | |
17 | ||
e6685141 | 18 | static void control_accept(struct event *); |
8429abe0 RW |
19 | static struct ctl_conn *control_connbyfd(int); |
20 | static struct ctl_conn *control_connbypid(pid_t); | |
21 | static void control_close(int); | |
e6685141 | 22 | static void control_dispatch_imsg(struct event *); |
8429abe0 RW |
23 | |
24 | struct ctl_conns ctl_conns; | |
25 | ||
26 | static int control_fd; | |
27 | ||
28 | int | |
274f5abf | 29 | control_init(char *path) |
8429abe0 | 30 | { |
e30090a6 | 31 | struct sockaddr_un s_un; |
8429abe0 RW |
32 | int fd; |
33 | mode_t old_umask; | |
34 | ||
eac6e3f0 | 35 | if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { |
8429abe0 RW |
36 | log_warn("%s: socket", __func__); |
37 | return (-1); | |
38 | } | |
eac6e3f0 | 39 | sock_set_nonblock(fd); |
8429abe0 | 40 | |
e30090a6 RW |
41 | memset(&s_un, 0, sizeof(s_un)); |
42 | s_un.sun_family = AF_UNIX; | |
274f5abf | 43 | strlcpy(s_un.sun_path, path, sizeof(s_un.sun_path)); |
8429abe0 | 44 | |
274f5abf | 45 | if (unlink(path) == -1) |
8429abe0 | 46 | if (errno != ENOENT) { |
274f5abf | 47 | log_warn("%s: unlink %s", __func__, path); |
8429abe0 RW |
48 | close(fd); |
49 | return (-1); | |
50 | } | |
51 | ||
52 | old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH); | |
e30090a6 | 53 | if (bind(fd, (struct sockaddr *)&s_un, sizeof(s_un)) == -1) { |
274f5abf | 54 | log_warn("%s: bind: %s", __func__, path); |
8429abe0 RW |
55 | close(fd); |
56 | umask(old_umask); | |
57 | return (-1); | |
58 | } | |
59 | umask(old_umask); | |
60 | ||
274f5abf | 61 | if (chmod(path, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) == -1) { |
8429abe0 RW |
62 | log_warn("%s: chmod", __func__); |
63 | close(fd); | |
274f5abf | 64 | (void)unlink(path); |
8429abe0 RW |
65 | return (-1); |
66 | } | |
67 | ||
68 | control_fd = fd; | |
69 | ||
70 | return (0); | |
71 | } | |
72 | ||
73 | int | |
74 | control_listen(void) | |
75 | { | |
76 | if (listen(control_fd, CONTROL_BACKLOG) == -1) { | |
77 | log_warn("%s: listen", __func__); | |
78 | return (-1); | |
79 | } | |
80 | ||
81 | return (accept_add(control_fd, control_accept, NULL)); | |
82 | } | |
83 | ||
84 | void | |
274f5abf | 85 | control_cleanup(char *path) |
8429abe0 RW |
86 | { |
87 | accept_del(control_fd); | |
88 | close(control_fd); | |
274f5abf | 89 | unlink(path); |
8429abe0 RW |
90 | } |
91 | ||
92 | /* ARGSUSED */ | |
e6685141 | 93 | static void control_accept(struct event *thread) |
8429abe0 RW |
94 | { |
95 | int connfd; | |
96 | socklen_t len; | |
e30090a6 | 97 | struct sockaddr_un s_un; |
8429abe0 RW |
98 | struct ctl_conn *c; |
99 | ||
e30090a6 | 100 | len = sizeof(s_un); |
e16d030c DS |
101 | if ((connfd = accept(EVENT_FD(thread), (struct sockaddr *)&s_un, |
102 | &len)) == -1) { | |
8429abe0 RW |
103 | /* |
104 | * Pause accept if we are out of file descriptors, or | |
105 | * libevent will haunt us here too. | |
106 | */ | |
107 | if (errno == ENFILE || errno == EMFILE) | |
108 | accept_pause(); | |
109 | else if (errno != EWOULDBLOCK && errno != EINTR && | |
110 | errno != ECONNABORTED) | |
eac6e3f0 | 111 | log_warn("%s: accept", __func__); |
cc9f21da | 112 | return; |
8429abe0 | 113 | } |
eac6e3f0 | 114 | sock_set_nonblock(connfd); |
8429abe0 RW |
115 | |
116 | if ((c = calloc(1, sizeof(struct ctl_conn))) == NULL) { | |
117 | log_warn(__func__); | |
118 | close(connfd); | |
cc9f21da | 119 | return; |
8429abe0 RW |
120 | } |
121 | ||
122 | imsg_init(&c->iev.ibuf, connfd); | |
eac6e3f0 | 123 | c->iev.handler_read = control_dispatch_imsg; |
66e78ae6 | 124 | c->iev.ev_read = NULL; |
907a2395 DS |
125 | event_add_read(master, c->iev.handler_read, &c->iev, c->iev.ibuf.fd, |
126 | &c->iev.ev_read); | |
eac6e3f0 RW |
127 | c->iev.handler_write = ldp_write_handler; |
128 | c->iev.ev_write = NULL; | |
8429abe0 RW |
129 | |
130 | TAILQ_INSERT_TAIL(&ctl_conns, c, entry); | |
131 | } | |
132 | ||
133 | static struct ctl_conn * | |
134 | control_connbyfd(int fd) | |
135 | { | |
136 | struct ctl_conn *c; | |
137 | ||
b53f7b86 RW |
138 | TAILQ_FOREACH(c, &ctl_conns, entry) { |
139 | if (c->iev.ibuf.fd == fd) | |
140 | break; | |
141 | } | |
8429abe0 RW |
142 | |
143 | return (c); | |
144 | } | |
145 | ||
146 | static struct ctl_conn * | |
147 | control_connbypid(pid_t pid) | |
148 | { | |
149 | struct ctl_conn *c; | |
150 | ||
b53f7b86 RW |
151 | TAILQ_FOREACH(c, &ctl_conns, entry) { |
152 | if (c->iev.ibuf.pid == pid) | |
153 | break; | |
154 | } | |
8429abe0 RW |
155 | |
156 | return (c); | |
157 | } | |
158 | ||
159 | static void | |
160 | control_close(int fd) | |
161 | { | |
162 | struct ctl_conn *c; | |
163 | ||
164 | if ((c = control_connbyfd(fd)) == NULL) { | |
165 | log_warnx("%s: fd %d: not found", __func__, fd); | |
166 | return; | |
167 | } | |
168 | ||
169 | msgbuf_clear(&c->iev.ibuf.w); | |
170 | TAILQ_REMOVE(&ctl_conns, c, entry); | |
171 | ||
e16d030c DS |
172 | EVENT_OFF(c->iev.ev_read); |
173 | EVENT_OFF(c->iev.ev_write); | |
8429abe0 RW |
174 | close(c->iev.ibuf.fd); |
175 | accept_unpause(); | |
176 | free(c); | |
177 | } | |
178 | ||
179 | /* ARGSUSED */ | |
e6685141 | 180 | static void control_dispatch_imsg(struct event *thread) |
8429abe0 | 181 | { |
e16d030c | 182 | int fd = EVENT_FD(thread); |
8429abe0 RW |
183 | struct ctl_conn *c; |
184 | struct imsg imsg; | |
185 | ssize_t n; | |
186 | unsigned int ifidx; | |
8429abe0 RW |
187 | |
188 | if ((c = control_connbyfd(fd)) == NULL) { | |
189 | log_warnx("%s: fd %d: not found", __func__, fd); | |
cc9f21da | 190 | return; |
8429abe0 RW |
191 | } |
192 | ||
eac6e3f0 RW |
193 | c->iev.ev_read = NULL; |
194 | ||
195 | if (((n = imsg_read(&c->iev.ibuf)) == -1 && errno != EAGAIN) || | |
196 | n == 0) { | |
197 | control_close(fd); | |
cc9f21da | 198 | return; |
8429abe0 RW |
199 | } |
200 | ||
201 | for (;;) { | |
202 | if ((n = imsg_get(&c->iev.ibuf, &imsg)) == -1) { | |
203 | control_close(fd); | |
cc9f21da | 204 | return; |
8429abe0 RW |
205 | } |
206 | ||
207 | if (n == 0) | |
208 | break; | |
209 | ||
210 | switch (imsg.hdr.type) { | |
211 | case IMSG_CTL_FIB_COUPLE: | |
212 | case IMSG_CTL_FIB_DECOUPLE: | |
213 | case IMSG_CTL_RELOAD: | |
8429abe0 RW |
214 | case IMSG_CTL_KROUTE: |
215 | case IMSG_CTL_KROUTE_ADDR: | |
216 | case IMSG_CTL_IFINFO: | |
eac6e3f0 | 217 | /* ignore */ |
8429abe0 RW |
218 | break; |
219 | case IMSG_CTL_SHOW_INTERFACE: | |
220 | if (imsg.hdr.len == IMSG_HEADER_SIZE + | |
221 | sizeof(ifidx)) { | |
222 | memcpy(&ifidx, imsg.data, sizeof(ifidx)); | |
223 | ldpe_iface_ctl(c, ifidx); | |
224 | imsg_compose_event(&c->iev, IMSG_CTL_END, 0, | |
225 | 0, -1, NULL, 0); | |
226 | } | |
227 | break; | |
228 | case IMSG_CTL_SHOW_DISCOVERY: | |
229 | ldpe_adj_ctl(c); | |
230 | break; | |
bc0eb287 RW |
231 | case IMSG_CTL_SHOW_DISCOVERY_DTL: |
232 | ldpe_adj_detail_ctl(c); | |
233 | break; | |
8429abe0 RW |
234 | case IMSG_CTL_SHOW_LIB: |
235 | case IMSG_CTL_SHOW_L2VPN_PW: | |
236 | case IMSG_CTL_SHOW_L2VPN_BINDING: | |
237 | c->iev.ibuf.pid = imsg.hdr.pid; | |
238 | ldpe_imsg_compose_lde(imsg.hdr.type, 0, imsg.hdr.pid, | |
239 | imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE); | |
240 | break; | |
241 | case IMSG_CTL_SHOW_NBR: | |
242 | ldpe_nbr_ctl(c); | |
243 | break; | |
244 | case IMSG_CTL_CLEAR_NBR: | |
245 | if (imsg.hdr.len != IMSG_HEADER_SIZE + | |
246 | sizeof(struct ctl_nbr)) | |
247 | break; | |
248 | ||
249 | nbr_clear_ctl(imsg.data); | |
250 | break; | |
e1894ff7 KS |
251 | case IMSG_CTL_SHOW_LDP_SYNC: |
252 | ldpe_ldp_sync_ctl(c); | |
253 | break; | |
8429abe0 | 254 | case IMSG_CTL_LOG_VERBOSE: |
eac6e3f0 | 255 | /* ignore */ |
8429abe0 RW |
256 | break; |
257 | default: | |
258 | log_debug("%s: error handling imsg %d", __func__, | |
259 | imsg.hdr.type); | |
260 | break; | |
261 | } | |
262 | imsg_free(&imsg); | |
263 | } | |
264 | ||
265 | imsg_event_add(&c->iev); | |
266 | } | |
267 | ||
268 | int | |
269 | control_imsg_relay(struct imsg *imsg) | |
270 | { | |
271 | struct ctl_conn *c; | |
272 | ||
273 | if ((c = control_connbypid(imsg->hdr.pid)) == NULL) | |
274 | return (0); | |
275 | ||
276 | return (imsg_compose_event(&c->iev, imsg->hdr.type, 0, imsg->hdr.pid, | |
277 | -1, imsg->data, imsg->hdr.len - IMSG_HEADER_SIZE)); | |
278 | } |