1224006Shrs/*- 2224006Shrs * Copyright (C) 2011 Hiroki Sato <hrs@FreeBSD.org> 3224006Shrs * All rights reserved. 4224006Shrs * 5224006Shrs * Redistribution and use in source and binary forms, with or without 6224006Shrs * modification, are permitted provided that the following conditions 7224006Shrs * are met: 8224006Shrs * 1. Redistributions of source code must retain the above copyright 9224006Shrs * notice, this list of conditions and the following disclaimer. 10224006Shrs * 2. Redistributions in binary form must reproduce the above copyright 11224006Shrs * notice, this list of conditions and the following disclaimer in the 12224006Shrs * documentation and/or other materials provided with the distribution. 13224006Shrs * 14224006Shrs * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 15224006Shrs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16224006Shrs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17224006Shrs * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS 18224006Shrs * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19224006Shrs * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20224006Shrs * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 21224006Shrs * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22224006Shrs * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23224006Shrs * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24224006Shrs * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25224006Shrs * 26224006Shrs * $FreeBSD$ 27224006Shrs * 28224006Shrs */ 29224006Shrs 30224006Shrs#include <sys/queue.h> 31224006Shrs#include <sys/types.h> 32224006Shrs#include <sys/socket.h> 33224006Shrs#include <sys/stat.h> 34224006Shrs#include <sys/un.h> 35224006Shrs#include <sys/uio.h> 36224006Shrs#include <net/if.h> 37224006Shrs#include <net/if_dl.h> 38224006Shrs#include <netinet/in.h> 39224006Shrs#include <netinet/icmp6.h> 40224006Shrs#include <fcntl.h> 41224006Shrs#include <errno.h> 42224006Shrs#include <netdb.h> 43224006Shrs#include <unistd.h> 44225519Shrs#include <poll.h> 45224006Shrs#include <signal.h> 46224006Shrs#include <string.h> 47224006Shrs#include <stdarg.h> 48224006Shrs#include <stdio.h> 49224006Shrs#include <stdlib.h> 50224006Shrs#include <syslog.h> 51224006Shrs 52224006Shrs#include "rtadvd.h" 53224006Shrs#include "if.h" 54224006Shrs#include "pathnames.h" 55224006Shrs#include "control.h" 56224006Shrs 57225519Shrs#define CM_RECV_TIMEOUT 30 58225519Shrs 59224006Shrsint 60225519Shrscm_recv(int fd, char *buf) 61224006Shrs{ 62301803Sngie ssize_t n; 63224006Shrs struct ctrl_msg_hdr *cm; 64224006Shrs char *msg; 65225519Shrs struct pollfd pfds[1]; 66225519Shrs int i; 67224006Shrs 68224006Shrs syslog(LOG_DEBUG, "<%s> enter, fd=%d", __func__, fd); 69224006Shrs 70224006Shrs memset(buf, 0, CM_MSG_MAXLEN); 71224006Shrs cm = (struct ctrl_msg_hdr *)buf; 72224006Shrs msg = (char *)buf + sizeof(*cm); 73224006Shrs 74225519Shrs pfds[0].fd = fd; 75225519Shrs pfds[0].events = POLLIN; 76225519Shrs 77224006Shrs for (;;) { 78225519Shrs i = poll(pfds, sizeof(pfds)/sizeof(pfds[0]), 79225519Shrs CM_RECV_TIMEOUT); 80225519Shrs 81225519Shrs if (i == 0) 82224006Shrs continue; 83225519Shrs 84225519Shrs if (i < 0) { 85225519Shrs syslog(LOG_ERR, "<%s> poll error: %s", 86225519Shrs __func__, strerror(errno)); 87225519Shrs continue; 88224006Shrs } 89225519Shrs 90225519Shrs if (pfds[0].revents & POLLIN) { 91225519Shrs n = read(fd, cm, sizeof(*cm)); 92225519Shrs if (n < 0 && errno == EAGAIN) { 93225519Shrs syslog(LOG_DEBUG, 94225519Shrs "<%s> waiting...", __func__); 95225519Shrs continue; 96225519Shrs } 97225519Shrs break; 98225519Shrs } 99224006Shrs } 100224006Shrs 101301803Sngie if (n != (ssize_t)sizeof(*cm)) { 102224006Shrs syslog(LOG_WARNING, 103224006Shrs "<%s> received a too small message.", __func__); 104225519Shrs goto cm_recv_err; 105224006Shrs } 106224006Shrs if (cm->cm_len > CM_MSG_MAXLEN) { 107224006Shrs syslog(LOG_WARNING, 108224006Shrs "<%s> received a too large message.", __func__); 109225519Shrs goto cm_recv_err; 110224006Shrs } 111224006Shrs if (cm->cm_version != CM_VERSION) { 112224006Shrs syslog(LOG_WARNING, 113224006Shrs "<%s> version mismatch", __func__); 114225519Shrs goto cm_recv_err; 115224006Shrs } 116224006Shrs if (cm->cm_type >= CM_TYPE_MAX) { 117224006Shrs syslog(LOG_WARNING, 118224006Shrs "<%s> invalid msg type.", __func__); 119225519Shrs goto cm_recv_err; 120224006Shrs } 121224006Shrs 122224006Shrs syslog(LOG_DEBUG, 123224006Shrs "<%s> ctrl msg received: type=%d", __func__, 124224006Shrs cm->cm_type); 125224006Shrs 126301803Sngie if (cm->cm_len > sizeof(*cm)) { 127301803Sngie size_t msglen = cm->cm_len - sizeof(*cm); 128224006Shrs 129224006Shrs syslog(LOG_DEBUG, 130301803Sngie "<%s> ctrl msg has payload (len=%zu)", __func__, 131224006Shrs msglen); 132224006Shrs 133224006Shrs for (;;) { 134225519Shrs i = poll(pfds, sizeof(pfds)/sizeof(pfds[0]), 135225519Shrs CM_RECV_TIMEOUT); 136225519Shrs 137225519Shrs if (i == 0) 138224006Shrs continue; 139225519Shrs 140225519Shrs if (i < 0) { 141225519Shrs syslog(LOG_ERR, "<%s> poll error: %s", 142225519Shrs __func__, strerror(errno)); 143225519Shrs continue; 144224006Shrs } 145225519Shrs 146225519Shrs if (pfds[0].revents & POLLIN) { 147225519Shrs n = read(fd, msg, msglen); 148225519Shrs if (n < 0 && errno == EAGAIN) { 149225519Shrs syslog(LOG_DEBUG, 150225519Shrs "<%s> waiting...", __func__); 151225519Shrs continue; 152225519Shrs } 153225519Shrs } 154224006Shrs break; 155224006Shrs } 156301803Sngie if (n != (ssize_t)msglen) { 157224006Shrs syslog(LOG_WARNING, 158224006Shrs "<%s> payload size mismatch.", __func__); 159225519Shrs goto cm_recv_err; 160224006Shrs } 161224006Shrs buf[CM_MSG_MAXLEN - 1] = '\0'; 162224006Shrs } 163224006Shrs 164224006Shrs return (0); 165224006Shrs 166225519Shrscm_recv_err: 167224006Shrs close(fd); 168224006Shrs return (-1); 169224006Shrs} 170224006Shrs 171224006Shrsint 172225519Shrscm_send(int fd, char *buf) 173224006Shrs{ 174224006Shrs struct iovec iov[2]; 175224006Shrs int iovcnt; 176224006Shrs ssize_t len; 177224006Shrs ssize_t iov_len_total; 178224006Shrs struct ctrl_msg_hdr *cm; 179224006Shrs char *msg; 180224006Shrs 181224006Shrs cm = (struct ctrl_msg_hdr *)buf; 182224006Shrs msg = (char *)buf + sizeof(*cm); 183224006Shrs 184224006Shrs iovcnt = 1; 185224006Shrs iov[0].iov_base = cm; 186224006Shrs iov[0].iov_len = sizeof(*cm); 187224006Shrs iov_len_total = iov[0].iov_len; 188224006Shrs if (cm->cm_len > sizeof(*cm)) { 189224006Shrs iovcnt++; 190224006Shrs iov[1].iov_base = msg; 191224006Shrs iov[1].iov_len = cm->cm_len - iov[0].iov_len; 192224006Shrs iov_len_total += iov[1].iov_len; 193224006Shrs } 194224006Shrs 195224006Shrs syslog(LOG_DEBUG, 196224144Shrs "<%s> ctrl msg send: type=%d, count=%d, total_len=%zd", __func__, 197224006Shrs cm->cm_type, iovcnt, iov_len_total); 198224006Shrs 199224006Shrs len = writev(fd, iov, iovcnt); 200224006Shrs syslog(LOG_DEBUG, 201224144Shrs "<%s> ctrl msg send: length=%zd", __func__, len); 202224006Shrs 203224006Shrs if (len == -1) { 204224006Shrs syslog(LOG_DEBUG, 205224006Shrs "<%s> write failed: (%d)%s", __func__, errno, 206224006Shrs strerror(errno)); 207224006Shrs close(fd); 208224006Shrs return (-1); 209224006Shrs } 210224006Shrs 211224006Shrs syslog(LOG_DEBUG, 212224144Shrs "<%s> write length = %zd (actual)", __func__, len); 213224006Shrs syslog(LOG_DEBUG, 214224144Shrs "<%s> write length = %zd (expected)", __func__, iov_len_total); 215224006Shrs 216224006Shrs if (len != iov_len_total) { 217224006Shrs close(fd); 218224006Shrs return (-1); 219224006Shrs } 220224006Shrs 221224006Shrs return (0); 222224006Shrs} 223224006Shrs 224224006Shrsint 225224006Shrscsock_accept(struct sockinfo *s) 226224006Shrs{ 227224006Shrs struct sockaddr_un sun; 228224006Shrs int flags; 229224006Shrs int fd; 230224006Shrs 231224006Shrs sun.sun_len = sizeof(sun); 232224006Shrs if ((fd = accept(s->si_fd, (struct sockaddr *)&sun, 233224006Shrs (socklen_t *)&sun.sun_len)) == -1) { 234224006Shrs if (errno != EWOULDBLOCK && errno != EINTR) 235224006Shrs syslog(LOG_WARNING, "<%s> accept ", __func__); 236224006Shrs syslog(LOG_WARNING, "<%s> Xaccept: %s", __func__, strerror(errno)); 237224006Shrs return (-1); 238224006Shrs } 239224006Shrs if ((flags = fcntl(fd, F_GETFL, 0)) == -1) { 240224006Shrs syslog(LOG_WARNING, "<%s> fcntl F_GETFL", __func__); 241224006Shrs close(s->si_fd); 242224006Shrs return (-1); 243224006Shrs } 244224006Shrs if ((flags = fcntl(fd, F_SETFL, flags | O_NONBLOCK)) == -1) { 245224006Shrs syslog(LOG_WARNING, "<%s> fcntl F_SETFL", __func__); 246224006Shrs return (-1); 247224006Shrs } 248224006Shrs syslog(LOG_DEBUG, "<%s> accept connfd=%d, listenfd=%d", __func__, 249224006Shrs fd, s->si_fd); 250224006Shrs 251224006Shrs return (fd); 252224006Shrs} 253224006Shrs 254224006Shrsint 255224006Shrscsock_close(struct sockinfo *s) 256224006Shrs{ 257224006Shrs close(s->si_fd); 258224006Shrs unlink(s->si_name); 259224006Shrs syslog(LOG_DEBUG, "<%s> remove %s", __func__, s->si_name); 260224006Shrs return (0); 261224006Shrs} 262224006Shrs 263224006Shrsint 264224006Shrscsock_listen(struct sockinfo *s) 265224006Shrs{ 266224006Shrs if (s->si_fd == -1) { 267224006Shrs syslog(LOG_ERR, "<%s> listen failed", __func__); 268224006Shrs return (-1); 269224006Shrs } 270224006Shrs if (listen(s->si_fd, SOCK_BACKLOG) == -1) { 271224006Shrs syslog(LOG_ERR, "<%s> listen failed", __func__); 272224006Shrs return (-1); 273224006Shrs } 274224006Shrs 275224006Shrs return (0); 276224006Shrs} 277224006Shrs 278224006Shrsint 279224006Shrscsock_open(struct sockinfo *s, mode_t mode) 280224006Shrs{ 281224006Shrs int flags; 282224006Shrs struct sockaddr_un sun; 283224006Shrs mode_t old_umask; 284224006Shrs 285224006Shrs if (s == NULL) { 286224006Shrs syslog(LOG_ERR, "<%s> internal error.", __func__); 287224006Shrs exit(1); 288224006Shrs } 289224006Shrs if (s->si_name == NULL) 290224006Shrs s->si_name = _PATH_CTRL_SOCK; 291224006Shrs 292224006Shrs if ((s->si_fd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) { 293224006Shrs syslog(LOG_ERR, 294224006Shrs "<%s> cannot open control socket", __func__); 295224006Shrs return (-1); 296224006Shrs } 297224006Shrs memset(&sun, 0, sizeof(sun)); 298224006Shrs sun.sun_family = AF_UNIX; 299224006Shrs sun.sun_len = sizeof(sun); 300224006Shrs strlcpy(sun.sun_path, s->si_name, sizeof(sun.sun_path)); 301224006Shrs 302224006Shrs if (unlink(s->si_name) == -1) 303224006Shrs if (errno != ENOENT) { 304224006Shrs syslog(LOG_ERR, 305224006Shrs "<%s> unlink %s", __func__, s->si_name); 306224006Shrs close(s->si_fd); 307224006Shrs return (-1); 308224006Shrs } 309224006Shrs old_umask = umask(S_IXUSR|S_IXGRP|S_IXOTH); 310224006Shrs if (bind(s->si_fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) { 311224006Shrs syslog(LOG_ERR, 312224006Shrs "<%s> bind failed: %s", __func__, s->si_name); 313224006Shrs close(s->si_fd); 314224006Shrs umask(old_umask); 315224006Shrs return (-1); 316224006Shrs } 317224006Shrs umask(old_umask); 318224006Shrs if (chmod(s->si_name, mode) == -1) { 319224006Shrs syslog(LOG_ERR, 320224006Shrs "<%s> chmod failed: %s", __func__, s->si_name); 321224006Shrs goto csock_open_err; 322224006Shrs } 323224006Shrs if ((flags = fcntl(s->si_fd, F_GETFL, 0)) == -1) { 324224006Shrs syslog(LOG_ERR, 325224006Shrs "<%s> fcntl F_GETFL failed: %s", __func__, s->si_name); 326224006Shrs goto csock_open_err; 327224006Shrs } 328224006Shrs if ((flags = fcntl(s->si_fd, F_SETFL, flags | O_NONBLOCK)) == -1) { 329224006Shrs syslog(LOG_ERR, 330224006Shrs "<%s> fcntl F_SETFL failed: %s", __func__, s->si_name); 331224006Shrs goto csock_open_err; 332224006Shrs } 333224006Shrs 334224006Shrs return (s->si_fd); 335224006Shrs 336224006Shrscsock_open_err: 337224006Shrs close(s->si_fd); 338224006Shrs unlink(s->si_name); 339224006Shrs return (-1); 340224006Shrs} 341224006Shrs 342224006Shrsstruct ctrl_msg_pl * 343225519Shrscm_bin2pl(char *str, struct ctrl_msg_pl *cp) 344224006Shrs{ 345224006Shrs size_t len; 346224006Shrs size_t *lenp; 347224006Shrs char *p; 348224006Shrs 349224006Shrs memset(cp, 0, sizeof(*cp)); 350224006Shrs 351224006Shrs p = str; 352224006Shrs 353224006Shrs lenp = (size_t *)p; 354224006Shrs len = *lenp++; 355224006Shrs p = (char *)lenp; 356224144Shrs syslog(LOG_DEBUG, "<%s> len(ifname) = %zu", __func__, len); 357224006Shrs if (len > 0) { 358224006Shrs cp->cp_ifname = malloc(len + 1); 359224006Shrs if (cp->cp_ifname == NULL) { 360224006Shrs syslog(LOG_ERR, "<%s> malloc", __func__); 361224006Shrs exit(1); 362224006Shrs } 363224006Shrs memcpy(cp->cp_ifname, p, len); 364224006Shrs cp->cp_ifname[len] = '\0'; 365224006Shrs p += len; 366224006Shrs } 367224006Shrs 368224006Shrs lenp = (size_t *)p; 369224006Shrs len = *lenp++; 370224006Shrs p = (char *)lenp; 371224144Shrs syslog(LOG_DEBUG, "<%s> len(key) = %zu", __func__, len); 372224006Shrs if (len > 0) { 373224006Shrs cp->cp_key = malloc(len + 1); 374224006Shrs if (cp->cp_key == NULL) { 375224006Shrs syslog(LOG_ERR, "<%s> malloc", __func__); 376224006Shrs exit(1); 377224006Shrs } 378224006Shrs memcpy(cp->cp_key, p, len); 379224006Shrs cp->cp_key[len] = '\0'; 380224006Shrs p += len; 381224006Shrs } 382224006Shrs 383224006Shrs lenp = (size_t *)p; 384224006Shrs len = *lenp++; 385224006Shrs p = (char *)lenp; 386224144Shrs syslog(LOG_DEBUG, "<%s> len(val) = %zu", __func__, len); 387224006Shrs if (len > 0) { 388224006Shrs cp->cp_val = malloc(len + 1); 389224006Shrs if (cp->cp_val == NULL) { 390224006Shrs syslog(LOG_ERR, "<%s> malloc", __func__); 391224006Shrs exit(1); 392224006Shrs } 393224006Shrs memcpy(cp->cp_val, p, len); 394224006Shrs cp->cp_val[len] = '\0'; 395224006Shrs cp->cp_val_len = len; 396224006Shrs } else 397224006Shrs cp->cp_val_len = 0; 398224006Shrs 399224006Shrs return (cp); 400224006Shrs} 401224006Shrs 402224006Shrssize_t 403225519Shrscm_pl2bin(char *str, struct ctrl_msg_pl *cp) 404224006Shrs{ 405224006Shrs size_t len; 406224006Shrs size_t *lenp; 407224006Shrs char *p; 408224006Shrs struct ctrl_msg_hdr *cm; 409224006Shrs 410224006Shrs len = sizeof(size_t); 411224006Shrs if (cp->cp_ifname != NULL) 412224006Shrs len += strlen(cp->cp_ifname); 413224006Shrs len += sizeof(size_t); 414224006Shrs if (cp->cp_key != NULL) 415224006Shrs len += strlen(cp->cp_key); 416224006Shrs len += sizeof(size_t); 417224006Shrs if (cp->cp_val != NULL && cp->cp_val_len > 0) 418224006Shrs len += cp->cp_val_len; 419224006Shrs 420224006Shrs if (len > CM_MSG_MAXLEN - sizeof(*cm)) { 421224144Shrs syslog(LOG_DEBUG, "<%s> msg too long (len=%zu)", 422224006Shrs __func__, len); 423224006Shrs return (0); 424224006Shrs } 425224144Shrs syslog(LOG_DEBUG, "<%s> msglen=%zu", __func__, len); 426224006Shrs memset(str, 0, len); 427224006Shrs p = str; 428224006Shrs lenp = (size_t *)p; 429224006Shrs 430224006Shrs if (cp->cp_ifname != NULL) { 431224006Shrs *lenp++ = strlen(cp->cp_ifname); 432224006Shrs p = (char *)lenp; 433224006Shrs memcpy(p, cp->cp_ifname, strlen(cp->cp_ifname)); 434224006Shrs p += strlen(cp->cp_ifname); 435224006Shrs } else { 436224006Shrs *lenp++ = '\0'; 437224006Shrs p = (char *)lenp; 438224006Shrs } 439224006Shrs 440224006Shrs lenp = (size_t *)p; 441224006Shrs if (cp->cp_key != NULL) { 442224006Shrs *lenp++ = strlen(cp->cp_key); 443224006Shrs p = (char *)lenp; 444224006Shrs memcpy(p, cp->cp_key, strlen(cp->cp_key)); 445224006Shrs p += strlen(cp->cp_key); 446224006Shrs } else { 447224006Shrs *lenp++ = '\0'; 448224006Shrs p = (char *)lenp; 449224006Shrs } 450224006Shrs 451224006Shrs lenp = (size_t *)p; 452224006Shrs if (cp->cp_val != NULL && cp->cp_val_len > 0) { 453224006Shrs *lenp++ = cp->cp_val_len; 454224006Shrs p = (char *)lenp; 455224006Shrs memcpy(p, cp->cp_val, cp->cp_val_len); 456224006Shrs p += cp->cp_val_len; 457224006Shrs } else { 458224006Shrs *lenp++ = '\0'; 459224006Shrs p = (char *)lenp; 460224006Shrs } 461224006Shrs 462224006Shrs return (len); 463224006Shrs} 464224006Shrs 465224006Shrssize_t 466225519Shrscm_str2bin(char *bin, void *str, size_t len) 467224006Shrs{ 468224006Shrs struct ctrl_msg_hdr *cm; 469224006Shrs 470224006Shrs syslog(LOG_DEBUG, "<%s> enter", __func__); 471224006Shrs 472224006Shrs if (len > CM_MSG_MAXLEN - sizeof(*cm)) { 473224144Shrs syslog(LOG_DEBUG, "<%s> msg too long (len=%zu)", 474224006Shrs __func__, len); 475224006Shrs return (0); 476224006Shrs } 477224144Shrs syslog(LOG_DEBUG, "<%s> msglen=%zu", __func__, len); 478224006Shrs memcpy(bin, (char *)str, len); 479224006Shrs 480224006Shrs return (len); 481224006Shrs} 482224006Shrs 483224006Shrsvoid * 484225519Shrscm_bin2str(char *bin, void *str, size_t len) 485224006Shrs{ 486224006Shrs 487224006Shrs syslog(LOG_DEBUG, "<%s> enter", __func__); 488224006Shrs 489224006Shrs memcpy((char *)str, bin, len); 490224006Shrs 491224006Shrs return (str); 492224006Shrs} 493