]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - usr.sbin/rtadvd/control.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / usr.sbin / rtadvd / control.c
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$
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
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
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
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
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
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
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 *
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
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
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 *
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 }