xref: /dragonfly/usr.sbin/rtadvd/control.c (revision c17e6018cab90fba83aa80d4974cfbeb9a5e75ca)
1 /*-
2  * Copyright (C) 2011 Hiroki Sato <hrs@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS
18  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
21  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
24  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  * $FreeBSD: stable/10/usr.sbin/rtadvd/control.c 225519 2011-09-12 23:52:55Z hrs $
27  *
28  */
29 
30 #include <sys/queue.h>
31 #include <sys/types.h>
32 #include <sys/socket.h>
33 #include <sys/stat.h>
34 #include <sys/un.h>
35 #include <sys/uio.h>
36 #include <net/if.h>
37 #include <net/if_dl.h>
38 #include <netinet/in.h>
39 #include <netinet/icmp6.h>
40 #include <fcntl.h>
41 #include <errno.h>
42 #include <netdb.h>
43 #include <unistd.h>
44 #include <poll.h>
45 #include <signal.h>
46 #include <string.h>
47 #include <stdarg.h>
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <syslog.h>
51 
52 #include "rtadvd.h"
53 #include "if.h"
54 #include "pathnames.h"
55 #include "control.h"
56 
57 #define   CM_RECV_TIMEOUT     30
58 
59 int
cm_recv(int fd,char * buf)60 cm_recv(int fd, char *buf)
61 {
62           int n;
63           struct ctrl_msg_hdr *cm;
64           char *msg;
65           struct pollfd pfds[1];
66           int i;
67 
68           syslog(LOG_DEBUG, "<%s> enter, fd=%d", __func__, fd);
69 
70           memset(buf, 0, CM_MSG_MAXLEN);
71           cm = (struct ctrl_msg_hdr *)buf;
72           msg = (char *)buf + sizeof(*cm);
73 
74           pfds[0].fd = fd;
75           pfds[0].events = POLLIN;
76 
77           for (;;) {
78                     i = poll(pfds, sizeof(pfds)/sizeof(pfds[0]),
79                         CM_RECV_TIMEOUT);
80 
81                     if (i == 0)
82                               continue;
83 
84                     if (i < 0) {
85                               syslog(LOG_ERR, "<%s> poll error: %s",
86                                   __func__, strerror(errno));
87                               continue;
88                     }
89 
90                     if (pfds[0].revents & POLLIN) {
91                               n = read(fd, cm, sizeof(*cm));
92                               if (n < 0 && errno == EAGAIN) {
93                                         syslog(LOG_DEBUG,
94                                             "<%s> waiting...", __func__);
95                                         continue;
96                               }
97                               break;
98                     }
99           }
100 
101           if (n != sizeof(*cm)) {
102                     syslog(LOG_WARNING,
103                         "<%s> received a too small message.", __func__);
104                     goto cm_recv_err;
105           }
106           if (cm->cm_len > CM_MSG_MAXLEN) {
107                     syslog(LOG_WARNING,
108                         "<%s> received a too large message.", __func__);
109                     goto cm_recv_err;
110           }
111           if (cm->cm_version != CM_VERSION) {
112                     syslog(LOG_WARNING,
113                         "<%s> version mismatch", __func__);
114                     goto cm_recv_err;
115           }
116           if (cm->cm_type >= CM_TYPE_MAX) {
117                     syslog(LOG_WARNING,
118                         "<%s> invalid msg type.", __func__);
119                     goto cm_recv_err;
120           }
121 
122           syslog(LOG_DEBUG,
123               "<%s> ctrl msg received: type=%d", __func__,
124               cm->cm_type);
125 
126           if (cm->cm_len > sizeof(cm)) {
127                     int msglen = cm->cm_len - sizeof(*cm);
128 
129                     syslog(LOG_DEBUG,
130                         "<%s> ctrl msg has payload (len=%d)", __func__,
131                         msglen);
132 
133                     for (;;) {
134                               i = poll(pfds, sizeof(pfds)/sizeof(pfds[0]),
135                                   CM_RECV_TIMEOUT);
136 
137                               if (i == 0)
138                                         continue;
139 
140                               if (i < 0) {
141                                         syslog(LOG_ERR, "<%s> poll error: %s",
142                                             __func__, strerror(errno));
143                                         continue;
144                               }
145 
146                               if (pfds[0].revents & POLLIN) {
147                                         n = read(fd, msg, msglen);
148                                         if (n < 0 && errno == EAGAIN) {
149                                                   syslog(LOG_DEBUG,
150                                                       "<%s> waiting...", __func__);
151                                                   continue;
152                                         }
153                               }
154                               break;
155                     }
156                     if (n != msglen) {
157                               syslog(LOG_WARNING,
158                                   "<%s> payload size mismatch.", __func__);
159                               goto cm_recv_err;
160                     }
161                     buf[CM_MSG_MAXLEN - 1] = '\0';
162           }
163 
164           return (0);
165 
166 cm_recv_err:
167           close(fd);
168           return (-1);
169 }
170 
171 int
cm_send(int fd,char * buf)172 cm_send(int fd, char *buf)
173 {
174           struct iovec iov[2];
175           int iovcnt;
176           ssize_t len;
177           ssize_t iov_len_total;
178           struct ctrl_msg_hdr *cm;
179           char *msg;
180 
181           cm = (struct ctrl_msg_hdr *)buf;
182           msg = (char *)buf + sizeof(*cm);
183 
184           iovcnt = 1;
185           iov[0].iov_base = cm;
186           iov[0].iov_len = sizeof(*cm);
187           iov_len_total = iov[0].iov_len;
188           if (cm->cm_len > sizeof(*cm)) {
189                     iovcnt++;
190                     iov[1].iov_base = msg;
191                     iov[1].iov_len = cm->cm_len - iov[0].iov_len;
192                     iov_len_total += iov[1].iov_len;
193           }
194 
195           syslog(LOG_DEBUG,
196               "<%s> ctrl msg send: type=%d, count=%d, total_len=%zd", __func__,
197               cm->cm_type, iovcnt, iov_len_total);
198 
199           len = writev(fd, iov, iovcnt);
200           syslog(LOG_DEBUG,
201               "<%s> ctrl msg send: length=%zd", __func__, len);
202 
203           if (len == -1) {
204                     syslog(LOG_DEBUG,
205                         "<%s> write failed: (%d)%s", __func__, errno,
206                         strerror(errno));
207                     close(fd);
208                     return (-1);
209           }
210 
211           syslog(LOG_DEBUG,
212               "<%s> write length = %zd (actual)", __func__, len);
213           syslog(LOG_DEBUG,
214               "<%s> write length = %zd (expected)", __func__, iov_len_total);
215 
216           if (len != iov_len_total) {
217                     close(fd);
218                     return (-1);
219           }
220 
221           return (0);
222 }
223 
224 int
csock_accept(struct sockinfo * s)225 csock_accept(struct sockinfo *s)
226 {
227           struct sockaddr_un  sun;
228           int       flags;
229           int       fd;
230 
231           sun.sun_len = sizeof(sun);
232           if ((fd = accept(s->si_fd, (struct sockaddr *)&sun,
233                         (socklen_t *)&sun.sun_len)) == -1) {
234                     if (errno != EWOULDBLOCK && errno != EINTR)
235                               syslog(LOG_WARNING, "<%s> accept ", __func__);
236                     syslog(LOG_WARNING, "<%s> Xaccept: %s", __func__, strerror(errno));
237                     return (-1);
238           }
239           if ((flags = fcntl(fd, F_GETFL, 0)) == -1) {
240                     syslog(LOG_WARNING, "<%s> fcntl F_GETFL", __func__);
241                     close(s->si_fd);
242                     return (-1);
243           }
244           if ((flags = fcntl(fd, F_SETFL, flags | O_NONBLOCK)) == -1) {
245                     syslog(LOG_WARNING, "<%s> fcntl F_SETFL", __func__);
246                     return (-1);
247           }
248           syslog(LOG_DEBUG, "<%s> accept connfd=%d, listenfd=%d", __func__,
249               fd, s->si_fd);
250 
251           return (fd);
252 }
253 
254 int
csock_close(struct sockinfo * s)255 csock_close(struct sockinfo *s)
256 {
257           close(s->si_fd);
258           unlink(s->si_name);
259           syslog(LOG_DEBUG, "<%s> remove %s", __func__, s->si_name);
260           return (0);
261 }
262 
263 int
csock_listen(struct sockinfo * s)264 csock_listen(struct sockinfo *s)
265 {
266           if (s->si_fd == -1) {
267                     syslog(LOG_ERR, "<%s> listen failed", __func__);
268                     return (-1);
269           }
270           if (listen(s->si_fd, SOCK_BACKLOG) == -1) {
271                     syslog(LOG_ERR, "<%s> listen failed", __func__);
272                     return (-1);
273           }
274 
275           return (0);
276 }
277 
278 int
csock_open(struct sockinfo * s,mode_t mode)279 csock_open(struct sockinfo *s, mode_t mode)
280 {
281           int flags;
282           struct sockaddr_un  sun;
283           mode_t    old_umask;
284 
285           if (s == NULL) {
286                     syslog(LOG_ERR, "<%s> internal error.", __func__);
287                     exit(1);
288           }
289           if (s->si_name == NULL)
290                     s->si_name = _PATH_CTRL_SOCK;
291 
292           if ((s->si_fd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) {
293                     syslog(LOG_ERR,
294                         "<%s> cannot open control socket", __func__);
295                     return (-1);
296           }
297           memset(&sun, 0, sizeof(sun));
298           sun.sun_family = AF_UNIX;
299           sun.sun_len = sizeof(sun);
300           strlcpy(sun.sun_path, s->si_name, sizeof(sun.sun_path));
301 
302           if (unlink(s->si_name) == -1)
303                     if (errno != ENOENT) {
304                               syslog(LOG_ERR,
305                                   "<%s> unlink %s", __func__, s->si_name);
306                               close(s->si_fd);
307                               return (-1);
308                     }
309           old_umask = umask(S_IXUSR|S_IXGRP|S_IXOTH);
310           if (bind(s->si_fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
311                     syslog(LOG_ERR,
312                         "<%s> bind failed: %s", __func__, s->si_name);
313                     close(s->si_fd);
314                     umask(old_umask);
315                     return (-1);
316           }
317           umask(old_umask);
318           if (chmod(s->si_name, mode) == -1) {
319                     syslog(LOG_ERR,
320                         "<%s> chmod failed: %s", __func__, s->si_name);
321                     goto csock_open_err;
322           }
323           if ((flags = fcntl(s->si_fd, F_GETFL, 0)) == -1) {
324                     syslog(LOG_ERR,
325                         "<%s> fcntl F_GETFL failed: %s", __func__, s->si_name);
326                     goto csock_open_err;
327           }
328           if ((flags = fcntl(s->si_fd, F_SETFL, flags | O_NONBLOCK)) == -1) {
329                     syslog(LOG_ERR,
330                         "<%s> fcntl F_SETFL failed: %s", __func__, s->si_name);
331                     goto csock_open_err;
332           }
333 
334           return (s->si_fd);
335 
336 csock_open_err:
337           close(s->si_fd);
338           unlink(s->si_name);
339           return (-1);
340 }
341 
342 struct ctrl_msg_pl *
cm_bin2pl(char * str,struct ctrl_msg_pl * cp)343 cm_bin2pl(char *str, struct ctrl_msg_pl *cp)
344 {
345           size_t len;
346           size_t *lenp;
347           char *p;
348 
349           memset(cp, 0, sizeof(*cp));
350 
351           p = str;
352 
353           lenp = (size_t *)p;
354           len = *lenp++;
355           p = (char *)lenp;
356           syslog(LOG_DEBUG, "<%s> len(ifname) = %zu", __func__, len);
357           if (len > 0) {
358                     cp->cp_ifname = malloc(len + 1);
359                     if (cp->cp_ifname == NULL) {
360                               syslog(LOG_ERR, "<%s> malloc", __func__);
361                               exit(1);
362                     }
363                     memcpy(cp->cp_ifname, p, len);
364                     cp->cp_ifname[len] = '\0';
365                     p += len;
366           }
367 
368           lenp = (size_t *)p;
369           len = *lenp++;
370           p = (char *)lenp;
371           syslog(LOG_DEBUG, "<%s> len(key) = %zu", __func__, len);
372           if (len > 0) {
373                     cp->cp_key = malloc(len + 1);
374                     if (cp->cp_key == NULL) {
375                               syslog(LOG_ERR, "<%s> malloc", __func__);
376                               exit(1);
377                     }
378                     memcpy(cp->cp_key, p, len);
379                     cp->cp_key[len] = '\0';
380                     p += len;
381           }
382 
383           lenp = (size_t *)p;
384           len = *lenp++;
385           p = (char *)lenp;
386           syslog(LOG_DEBUG, "<%s> len(val) = %zu", __func__, len);
387           if (len > 0) {
388                     cp->cp_val = malloc(len + 1);
389                     if (cp->cp_val == NULL) {
390                               syslog(LOG_ERR, "<%s> malloc", __func__);
391                               exit(1);
392                     }
393                     memcpy(cp->cp_val, p, len);
394                     cp->cp_val[len] = '\0';
395                     cp->cp_val_len = len;
396           } else
397                     cp->cp_val_len = 0;
398 
399           return (cp);
400 }
401 
402 size_t
cm_pl2bin(char * str,struct ctrl_msg_pl * cp)403 cm_pl2bin(char *str, struct ctrl_msg_pl *cp)
404 {
405           size_t len;
406           size_t *lenp;
407           char *p;
408           struct ctrl_msg_hdr *cm;
409 
410           len = sizeof(size_t);
411           if (cp->cp_ifname != NULL)
412                     len += strlen(cp->cp_ifname);
413           len += sizeof(size_t);
414           if (cp->cp_key != NULL)
415                     len += strlen(cp->cp_key);
416           len += sizeof(size_t);
417           if (cp->cp_val != NULL && cp->cp_val_len > 0)
418                     len += cp->cp_val_len;
419 
420           if (len > CM_MSG_MAXLEN - sizeof(*cm)) {
421                     syslog(LOG_DEBUG, "<%s> msg too long (len=%zu)",
422                         __func__, len);
423                     return (0);
424           }
425           syslog(LOG_DEBUG, "<%s> msglen=%zu", __func__, len);
426           memset(str, 0, len);
427           p = str;
428           lenp = (size_t *)p;
429 
430           if (cp->cp_ifname != NULL) {
431                     *lenp++ = strlen(cp->cp_ifname);
432                     p = (char *)lenp;
433                     memcpy(p, cp->cp_ifname, strlen(cp->cp_ifname));
434                     p += strlen(cp->cp_ifname);
435           } else {
436                     *lenp++ = '\0';
437                     p = (char *)lenp;
438           }
439 
440           lenp = (size_t *)p;
441           if (cp->cp_key != NULL) {
442                     *lenp++ = strlen(cp->cp_key);
443                     p = (char *)lenp;
444                     memcpy(p, cp->cp_key, strlen(cp->cp_key));
445                     p += strlen(cp->cp_key);
446           } else {
447                     *lenp++ = '\0';
448                     p = (char *)lenp;
449           }
450 
451           lenp = (size_t *)p;
452           if (cp->cp_val != NULL && cp->cp_val_len > 0) {
453                     *lenp++ = cp->cp_val_len;
454                     p = (char *)lenp;
455                     memcpy(p, cp->cp_val, cp->cp_val_len);
456                     p += cp->cp_val_len;
457           } else {
458                     *lenp++ = '\0';
459                     p = (char *)lenp;
460           }
461 
462           return (len);
463 }
464 
465 size_t
cm_str2bin(char * bin,void * str,size_t len)466 cm_str2bin(char *bin, void *str, size_t len)
467 {
468           struct ctrl_msg_hdr *cm;
469 
470           syslog(LOG_DEBUG, "<%s> enter", __func__);
471 
472           if (len > CM_MSG_MAXLEN - sizeof(*cm)) {
473                     syslog(LOG_DEBUG, "<%s> msg too long (len=%zu)",
474                         __func__, len);
475                     return (0);
476           }
477           syslog(LOG_DEBUG, "<%s> msglen=%zu", __func__, len);
478           memcpy(bin, (char *)str, len);
479 
480           return (len);
481 }
482 
483 void *
cm_bin2str(char * bin,void * str,size_t len)484 cm_bin2str(char *bin, void *str, size_t len)
485 {
486 
487           syslog(LOG_DEBUG, "<%s> enter", __func__);
488 
489           memcpy((char *)str, bin, len);
490 
491           return (str);
492 }
493