1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (C) 2011 Hiroki Sato <hrs@FreeBSD.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 25 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 26 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 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 ssize_t 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 != (ssize_t)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 size_t msglen = cm->cm_len - sizeof(*cm); 128 129 syslog(LOG_DEBUG, 130 "<%s> ctrl msg has payload (len=%zu)", __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 != (ssize_t)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 } 493