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