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