1/* 2 * Copyright (c) 2018 3 * Hartmut Brandt. 4 * All rights reserved. 5 * 6 * Author: Harti Brandt <harti@freebsd.org> 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * $Begemot: bsnmp/snmpd/trans_udp.c,v 1.5 2005/10/04 08:46:56 brandt_h Exp $ 30 * 31 * Internet transport 32 */ 33 34#include <sys/param.h> 35#include <sys/socket.h> 36#include <sys/types.h> 37 38#include <assert.h> 39#include <errno.h> 40#include <netdb.h> 41#include <stdbool.h> 42#include <stddef.h> 43#include <stdlib.h> 44#include <string.h> 45#include <syslog.h> 46#include <unistd.h> 47 48#include <stdio.h> 49 50#include <arpa/inet.h> 51 52#include "asn1.h" 53#include "snmp.h" 54#include "snmpmod.h" 55 56#include "snmpd.h" 57 58#define SNMPTREE_TYPES 59#define SNMPENUM_FUNCS 60#include "tree.h" 61#include "oid.h" 62 63extern const struct transport_def inet_trans; 64 65struct inet_port; 66struct inet_port_params; 67struct port_sock; 68 69typedef int create_func(struct inet_port *, struct inet_port_params *); 70typedef void input_func(int, void *); 71typedef int activate_func(struct inet_port *); 72typedef void deactivate_func(struct inet_port *); 73typedef void parse_ctrl_func(struct port_sock *, const struct msghdr *); 74typedef void setsrc_func(struct port_sock *, struct msghdr *, char *); 75 76static create_func ipv4_create; 77static input_func ipv4_input; 78static activate_func ipv4_activate; 79static deactivate_func ipv4_deactivate; 80static parse_ctrl_func ipv4_parse_ctrl; 81static setsrc_func ipv4_setsrc; 82 83static create_func ipv6_create; 84static input_func ipv6_input; 85static activate_func ipv6_activate; 86static deactivate_func ipv6_deactivate; 87static parse_ctrl_func ipv6_parse_ctrl; 88static setsrc_func ipv6_setsrc; 89 90static create_func ipv6z_create; 91 92static create_func dns_create; 93static activate_func dns_activate; 94static deactivate_func dns_deactivate; 95 96struct port_sock { 97 /* common input stuff; must be first */ 98 struct port_input input; 99 100 /** link field */ 101 TAILQ_ENTRY(port_sock) link; 102 103 /** pointer to parent */ 104 struct inet_port *port; 105 106 /** bind address */ 107 struct sockaddr_storage bind_addr; 108 109 /** reply destination */ 110 struct sockaddr_storage ret_dest; 111 112 /** need to set source address in reply; set for INADDR_ANY */ 113 bool set_ret_source; 114 115 /** address of the receive interface */ 116 union { 117 /** IPv4 case */ 118 struct in_addr a4; 119 120 /** IPv6 case */ 121 struct in6_pktinfo a6; 122 } ret_source; 123 124 /** parse control message */ 125 parse_ctrl_func *parse_ctrl; 126 127 /** set source address for a send() */ 128 setsrc_func *setsrc; 129}; 130static_assert(offsetof(struct port_sock, input) == 0, 131 "input not first in port_sock"); 132 133/** 134 * Table row for the inet ports. 135 * 136 * When actived each row can have one or several open sockets. For ipv6, 137 * ipv4 and ipv6z addresses it is always one, for dns addresses more than 138 * one socket can be open. 139 */ 140struct inet_port { 141 /** common i/o port stuff (must be first) */ 142 struct tport tport; 143 144 /** transport protocol */ 145 enum BegemotSnmpdTransportProto proto; 146 147 /** row status */ 148 enum RowStatus row_status; 149 150 /** socket list */ 151 TAILQ_HEAD(, port_sock) socks; 152 153 /** value for InetAddressType::dns */ 154 char *dns_addr; 155 156 /** port number in dns case; network byte order */ 157 uint16_t dns_port; 158 159 /** create a port */ 160 create_func *create; 161 162 /** activate a port */ 163 activate_func *activate; 164 165 /** deactivate port */ 166 deactivate_func *deactivate; 167}; 168static_assert(offsetof(struct inet_port, tport) == 0, 169 "tport not first in inet_port"); 170 171/** to be used in bind_addr field */ 172#define AF_DNS AF_VENDOR00 173 174/** registered transport */ 175static struct transport *my_trans; 176 177/** set operation */ 178enum { 179 SET_CREATED, 180 SET_ACTIVATED, 181 SET_DEACTIVATE, 182 SET_DESTROY, 183}; 184 185/** length of the control data buffer */ 186static const size_t RECV_CBUF_SIZE = 187 MAX(CMSG_SPACE(SOCKCREDSIZE(CMGROUP_MAX)) + 188 CMSG_SPACE(sizeof(struct in_addr)), 189 CMSG_SPACE(SOCKCREDSIZE(CMGROUP_MAX)) + 190 CMSG_SPACE(sizeof(struct in6_pktinfo))); 191 192/** length of the control data buffer */ 193static const size_t XMIT_CBUF_SIZE = 194 MAX(CMSG_SPACE(sizeof(struct in_addr)), 195 CMSG_SPACE(sizeof(struct in6_pktinfo))); 196 197/** 198 * Start the transport. This registers the transport with the 199 * transport table. 200 * 201 * \return SNMP error code 202 */ 203static int 204inet_start(void) 205{ 206 return (trans_register(&inet_trans, &my_trans)); 207} 208 209/** 210 * Stop the transport. This tries to unregister the transport which 211 * in turn fails if the list of ports is not empty. 212 * 213 * \return SNMP error code 214 */ 215static int 216inet_stop(int force __unused) 217{ 218 if (my_trans != NULL) 219 if (trans_unregister(my_trans) != 0) 220 return (SNMP_ERR_GENERR); 221 return (SNMP_ERR_NOERROR); 222} 223 224/** 225 * Deactivate SNMP port. 226 * 227 * \param tp port to close 228 */ 229static void 230deactivate_port(struct inet_port *p) 231{ 232 p->deactivate(p); 233} 234 235/* 236 * This function activates a port. For ports opened via the config files 237 * this is called just before entering the event loop. For ports create 238 * during runtime this is called when the RowStatus is set to Active or 239 * as second step for CreateAndGo. 240 * 241 * \param tp transport port 242 * 243 * \return SNMP error code 244 */ 245static int 246inet_activate(struct tport *tp) 247{ 248 struct inet_port *port = (struct inet_port *)tp; 249 250 return (port->activate(port)); 251} 252 253/* 254 * Close the SNMP port if it is open and destroy it. 255 * 256 * \param tp port to close 257 */ 258static void 259inet_destroy_port(struct tport *tp) 260{ 261 struct inet_port *port = (struct inet_port *)tp; 262 263 deactivate_port(port); 264 265 trans_remove_port(tp); 266 267 free(port->dns_addr); 268 free(port); 269} 270 271/** 272 * If the input struct has no buffer allocated yet, do it now. If allocation 273 * fails, read the data into a local buffer and drop it. 274 * 275 * \param pi input struct 276 * 277 * \return -1 if allocation fails, 0 otherwise 278 */ 279static int 280inet_alloc_buf(struct port_input *pi) 281{ 282 char drop_buf[2000]; 283 284 if (pi->buf == NULL) { 285 if ((pi->buf = buf_alloc(0)) == NULL) { 286 (void)recvfrom(pi->fd, drop_buf, sizeof(drop_buf), 287 0, NULL, NULL); 288 return (-1); 289 } 290 pi->buflen = buf_size(0); 291 } 292 return (0); 293} 294 295/** 296 * Read message into input buffer. Get also the source address and any 297 * control data that is available. If the message is truncated, increment 298 * corresponding statistics. 299 * 300 * \param pi input object 301 * \param msg message object to fill 302 * \param cbuf control data buffer 303 * 304 * \return -1 when something goes wrong, 0 othersise 305 */ 306static int 307inet_read_msg(struct port_input *pi, struct msghdr *msg, char *cbuf) 308{ 309 struct iovec iov[1]; 310 311 iov[0].iov_base = pi->buf; 312 iov[0].iov_len = pi->buflen; 313 314 msg->msg_name = pi->peer; 315 msg->msg_namelen = pi->peerlen; 316 msg->msg_iov = iov; 317 msg->msg_iovlen = 1; 318 msg->msg_control = cbuf; 319 msg->msg_controllen = RECV_CBUF_SIZE; 320 msg->msg_flags = 0; 321 322 memset(cbuf, 0, RECV_CBUF_SIZE); 323 324 const ssize_t len = recvmsg(pi->fd, msg, 0); 325 326 if (len == -1 || len == 0) 327 /* receive error */ 328 return (-1); 329 330 if (msg->msg_flags & MSG_TRUNC) { 331 /* truncated - drop */ 332 snmpd_stats.silentDrops++; 333 snmpd_stats.inTooLong++; 334 return (-1); 335 } 336 337 pi->length = (size_t)len; 338 339 return (0); 340} 341 342/* 343 * Input available on socket. 344 * 345 * \param tp transport port 346 * \param pi input struct 347 * 348 * \return number of bytes received 349 */ 350static ssize_t 351inet_recv(struct tport *tp, struct port_input *pi) 352{ 353 struct inet_port *port = __containerof(tp, struct inet_port, tport); 354 struct port_sock *sock = __containerof(pi, struct port_sock, input); 355 356 assert(port->proto == BegemotSnmpdTransportProto_udp); 357 358 if (inet_alloc_buf(pi) == -1) 359 return (-1); 360 361 char cbuf[RECV_CBUF_SIZE]; 362 struct msghdr msg; 363 364 if (inet_read_msg(pi, &msg, cbuf) == -1) 365 return (-1); 366 367 sock->parse_ctrl(sock, &msg); 368 369 return (0); 370} 371 372/* 373 * Send message. 374 * 375 * \param tp port 376 * \param buf data to send 377 * \param len number of bytes to send 378 * \param addr destination address 379 * \param addlen destination address length 380 * 381 * \return number of bytes sent 382 */ 383static ssize_t 384inet_send2(struct tport *tp, const u_char *buf, size_t len, 385 struct port_input *pi) 386{ 387 struct inet_port *p = __containerof(tp, struct inet_port, tport); 388 struct port_sock *s = (pi == NULL) ? TAILQ_FIRST(&p->socks) : 389 __containerof(pi, struct port_sock, input); 390 391 struct iovec iov; 392 393 iov.iov_base = __DECONST(void*, buf); 394 iov.iov_len = len; 395 396 struct msghdr msg; 397 398 msg.msg_flags = 0; 399 msg.msg_iov = &iov; 400 msg.msg_iovlen = 1; 401 msg.msg_name = (void *)pi->peer; 402 msg.msg_namelen = pi->peerlen; 403 404 char cbuf[XMIT_CBUF_SIZE]; 405 if (s->set_ret_source) { 406 s->setsrc(s, &msg, cbuf); 407 } else { 408 msg.msg_control = NULL; 409 msg.msg_controllen = 0; 410 } 411 412 return (sendmsg(s->input.fd, &msg, 0)); 413} 414 415/** exported to daemon */ 416const struct transport_def inet_trans = { 417 "inet", 418 OIDX_begemotSnmpdTransInet, 419 inet_start, 420 inet_stop, 421 inet_destroy_port, 422 inet_activate, 423 NULL, 424 inet_recv, 425 inet_send2, 426}; 427 428struct inet_port_params { 429 /** index oid */ 430 struct asn_oid index; 431 432 /** internet address type */ 433 enum InetAddressType type; 434 435 /** internet address */ 436 u_char *addr; 437 438 /** length of address */ 439 size_t addr_len; 440 441 /** port number */ 442 uint32_t port; 443 444 /** protocol */ 445 enum BegemotSnmpdTransportProto proto; 446}; 447 448/** 449 * IPv4 creation stuff. Parse the index, fill socket address and creates 450 * a port_sock. 451 * 452 * \param port the port to create 453 * \param params parameters from the SNMP SET 454 * 455 * \return SNMP error 456 */ 457static int 458ipv4_create(struct inet_port *port, struct inet_port_params *params) 459{ 460 461 if (params->addr_len != 4) 462 return (SNMP_ERR_INCONS_VALUE); 463 464 struct port_sock *sock = calloc(1, sizeof(struct port_sock)); 465 if (sock == NULL) 466 return (SNMP_ERR_GENERR); 467 468 snmpd_input_init(&sock->input); 469 470 TAILQ_INSERT_HEAD(&port->socks, sock, link); 471 472 struct sockaddr_in *sin = 473 (struct sockaddr_in *)&sock->bind_addr; 474 475 sin->sin_len = sizeof(struct sockaddr_in); 476 sin->sin_family = AF_INET; 477 sin->sin_port = htons(params->port); 478 memcpy(&sin->sin_addr, params->addr, 4); /* network byte order */ 479 480 sock->port = port; 481 482 return (SNMP_ERR_NOERROR); 483} 484 485/* 486 * An IPv4 inet port is ready. Delegate to the generic code to read the data 487 * and react. 488 * 489 * \param fd file descriptor that is ready 490 * \param udata inet_port pointer 491 */ 492static void 493ipv4_input(int fd __unused, void *udata) 494{ 495 struct port_sock *sock = udata; 496 497 sock->input.peerlen = sizeof(struct sockaddr_in); 498 snmpd_input(&sock->input, &sock->port->tport); 499} 500 501/** 502 * Activate an IPv4 socket. 503 * 504 * \param sock thhe socket to activate 505 * 506 * \return error code 507 */ 508static int 509ipv4_activate_sock(struct port_sock *sock) 510{ 511 if ((sock->input.fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1) { 512 syslog(LOG_ERR, "creating UDP4 socket: %m"); 513 return (SNMP_ERR_RES_UNAVAIL); 514 } 515 516 const struct sockaddr_in *sin = 517 (const struct sockaddr_in *)&sock->bind_addr; 518 519 if (sin->sin_addr.s_addr == INADDR_ANY) { 520 /* need to know from which address to return */ 521 static const int on = 1; 522 523 if (setsockopt(sock->input.fd, IPPROTO_IP, IP_RECVDSTADDR, &on, 524 sizeof(on)) == -1) { 525 syslog(LOG_ERR, "setsockopt(IP_RECVDSTADDR): %m"); 526 (void)close(sock->input.fd); 527 sock->input.fd = -1; 528 return (SNMP_ERR_GENERR); 529 } 530 sock->set_ret_source = true; 531 } 532 533 if (bind(sock->input.fd, (const struct sockaddr *)sin, sizeof(*sin))) { 534 if (errno == EADDRNOTAVAIL) { 535 (void)close(sock->input.fd); 536 sock->input.fd = -1; 537 return (SNMP_ERR_INCONS_NAME); 538 } 539 syslog(LOG_ERR, "bind: %s:%u %m", inet_ntoa(sin->sin_addr), 540 ntohs(sin->sin_port)); 541 (void)close(sock->input.fd); 542 sock->input.fd = -1; 543 return (SNMP_ERR_GENERR); 544 } 545 546 if ((sock->input.id = fd_select(sock->input.fd, ipv4_input, 547 sock, NULL)) == NULL) { 548 (void)close(sock->input.fd); 549 sock->input.fd = -1; 550 return (SNMP_ERR_GENERR); 551 } 552 sock->input.peer = (struct sockaddr *)&sock->ret_dest; 553 554 sock->parse_ctrl = ipv4_parse_ctrl; 555 sock->setsrc = ipv4_setsrc; 556 557 return (SNMP_ERR_NOERROR); 558} 559 560/** 561 * Open an IPv4 socket. Make the socket, bind it and put it on the select 562 * list. The socket struct has already been created during creation. 563 * 564 * \param p inet port 565 * 566 * \return SNMP error code 567 */ 568static int 569ipv4_activate(struct inet_port *p) 570{ 571 struct port_sock *sock = TAILQ_FIRST(&p->socks); 572 assert(sock); 573 assert(!TAILQ_NEXT(sock, link)); 574 575 const int ret = ipv4_activate_sock(sock); 576 if (ret == SNMP_ERR_NOERROR) 577 p->row_status = RowStatus_active; 578 579 return (ret); 580} 581 582/** 583 * Close an IPv4 socket. Keep the sock object. 584 * 585 * \param p inet port 586 */ 587static void 588ipv4_deactivate(struct inet_port *p) 589{ 590 struct port_sock *sock = TAILQ_FIRST(&p->socks); 591 assert(sock); 592 assert(!TAILQ_NEXT(sock, link)); 593 594 snmpd_input_close(&sock->input); 595 596 p->row_status = RowStatus_notInService; 597} 598 599/** 600 * Parse the control data received with a UDPv4 packet. This may contain 601 * credentials (for a local connection) and the address of the interface 602 * the message was received on. If there are credentials set the priv flag 603 * if the effective UID is zero. 604 * 605 * \param sock the sock object 606 * \param msg the received message 607 */ 608static void 609ipv4_parse_ctrl(struct port_sock *sock, const struct msghdr *msg) 610{ 611 struct sockcred *cred = NULL; 612 613 for (struct cmsghdr *cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; 614 cmsg = CMSG_NXTHDR(msg, cmsg)) { 615 616 if (cmsg->cmsg_level == IPPROTO_IP && 617 cmsg->cmsg_type == IP_RECVDSTADDR) { 618 memcpy(&sock->ret_source.a4, CMSG_DATA(cmsg), 619 sizeof(struct in_addr)); 620 621 } else if (cmsg->cmsg_level == SOL_SOCKET && 622 cmsg->cmsg_type == SCM_CREDS) { 623 cred = (struct sockcred *)(void *)CMSG_DATA(cmsg); 624 } 625 } 626 627 sock->input.priv = 0; 628 if (sock->input.cred && cred) 629 /* remote end has sent credentials */ 630 sock->input.priv = (cred->sc_euid == 0); 631} 632 633/** 634 * Set the source address option for IPv4 sockets. 635 * 636 * \param sock socket object 637 * \param msg message 638 */ 639static void 640ipv4_setsrc(struct port_sock *sock, struct msghdr *msg, char *cbuf) 641{ 642 struct cmsghdr *cmsg; 643 644 msg->msg_control = cbuf; 645 msg->msg_controllen = CMSG_SPACE(sizeof(struct in_addr)); 646 647 /* select outgoing interface by setting source address */ 648 cmsg = CMSG_FIRSTHDR(msg); 649 cmsg->cmsg_level = IPPROTO_IP; 650 cmsg->cmsg_type = IP_SENDSRCADDR; 651 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr)); 652 memcpy(CMSG_DATA(cmsg), &sock->ret_source.a4, 653 sizeof(struct in_addr)); 654} 655 656/** 657 * Common part of IPv6 creation. This is used by both ipv6_create() and 658 * ipv6z_create(). 659 * 660 * \param port the table row 661 * \param params creation parameters 662 * \param scope_id scope_id (0 or from index) 663 * 664 * \return SNMP_ERR_NOERROR if port has been created, error code otherwise 665 */ 666static int 667ipv6_create_common(struct inet_port *port, struct inet_port_params *params, 668 u_int scope_id) 669{ 670 struct port_sock *sock = calloc(1, sizeof(struct port_sock)); 671 672 if (sock == NULL) 673 return (SNMP_ERR_GENERR); 674 675 struct sockaddr_in6 *sin = (struct sockaddr_in6 *)&sock->bind_addr; 676 677 sin->sin6_len = sizeof(struct sockaddr_in6); 678 sin->sin6_family = AF_INET6; 679 sin->sin6_port = htons(params->port); 680 sin->sin6_flowinfo = 0; 681 sin->sin6_scope_id = scope_id; 682 683 memcpy(sin->sin6_addr.s6_addr, params->addr, 16); 684 685 if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) && scope_id == 0) { 686 char buf[INET6_ADDRSTRLEN]; 687 syslog(LOG_INFO, "%s: link local address used without scope " 688 "index: %s", __func__, inet_ntop(AF_INET6, 689 &sin->sin6_addr, buf, sizeof(buf))); 690 free(sock); 691 return (SNMP_ERR_NO_CREATION); 692 } 693 694 sock->port = port; 695 696 snmpd_input_init(&sock->input); 697 TAILQ_INSERT_HEAD(&port->socks, sock, link); 698 699 return (SNMP_ERR_NOERROR); 700} 701 702/** 703 * IPv6 creation stuff. Parse the index, fill socket address and creates 704 * a port_sock. 705 * 706 * \param port the port to create 707 * \param params parameters from the SNMP SET 708 * 709 * \return SNMP error 710 */ 711static int 712ipv6_create(struct inet_port *port, struct inet_port_params *params) 713{ 714 if (params->addr_len != 16) 715 return (SNMP_ERR_INCONS_VALUE); 716 717 const int ret = ipv6_create_common(port, params, 0); 718 if (ret != SNMP_ERR_NOERROR) 719 return (ret); 720 721 return (SNMP_ERR_NOERROR); 722} 723 724/* 725 * An IPv6 inet port is ready. Delegate to the generic code to read the data 726 * and react. 727 * 728 * \param fd file descriptor that is ready 729 * \param udata inet_port pointer 730 */ 731static void 732ipv6_input(int fd __unused, void *udata) 733{ 734 struct port_sock *sock = udata; 735 736 sock->input.peerlen = sizeof(struct sockaddr_in6); 737 snmpd_input(&sock->input, &sock->port->tport); 738} 739 740/** 741 * Activate an IPv6 socket. 742 * 743 * \param sock thhe socket to activate 744 * 745 * \return error code 746 */ 747static int 748ipv6_activate_sock(struct port_sock *sock) 749{ 750 if ((sock->input.fd = socket(PF_INET6, SOCK_DGRAM, 0)) == -1) { 751 syslog(LOG_ERR, "creating UDP6 socket: %m"); 752 return (SNMP_ERR_RES_UNAVAIL); 753 } 754 755 const struct sockaddr_in6 *sin = 756 (const struct sockaddr_in6 *)&sock->bind_addr; 757 758 if (memcmp(&sin->sin6_addr, &in6addr_any, sizeof(in6addr_any)) == 0) { 759 /* need to know from which address to return */ 760 static const int on = 1; 761 762 if (setsockopt(sock->input.fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, 763 &on, sizeof(on)) == -1) { 764 syslog(LOG_ERR, "setsockopt(IP6_PKTINFO): %m"); 765 (void)close(sock->input.fd); 766 sock->input.fd = -1; 767 return (SNMP_ERR_GENERR); 768 } 769 sock->set_ret_source = true; 770 } 771 772 if (bind(sock->input.fd, (const struct sockaddr *)sin, sizeof(*sin))) { 773 if (community != COMM_INITIALIZE && errno == EADDRNOTAVAIL) { 774 (void)close(sock->input.fd); 775 sock->input.fd = -1; 776 return (SNMP_ERR_INCONS_NAME); 777 } 778 char buf[INET6_ADDRSTRLEN]; 779 syslog(LOG_ERR, "bind: %s:%u:%u %m", inet_ntop(AF_INET6, 780 &sin->sin6_addr, buf, sizeof(buf)), sin->sin6_scope_id, 781 ntohs(sin->sin6_port)); 782 (void)close(sock->input.fd); 783 sock->input.fd = -1; 784 return (SNMP_ERR_GENERR); 785 } 786 if ((sock->input.id = fd_select(sock->input.fd, ipv6_input, 787 sock, NULL)) == NULL) { 788 (void)close(sock->input.fd); 789 sock->input.fd = -1; 790 return (SNMP_ERR_GENERR); 791 } 792 sock->input.peer = (struct sockaddr *)&sock->ret_dest; 793 794 sock->parse_ctrl = ipv6_parse_ctrl; 795 sock->setsrc = ipv6_setsrc; 796 797 return (SNMP_ERR_NOERROR); 798} 799 800/** 801 * Open an IPv6 socket. 802 * 803 * \param port inet port 804 * 805 * \return SNMP error code 806 */ 807static int 808ipv6_activate(struct inet_port *p) 809{ 810 struct port_sock *sock = TAILQ_FIRST(&p->socks); 811 assert(sock); 812 813 const int ret = ipv6_activate_sock(sock); 814 815 if (ret == SNMP_ERR_NOERROR) 816 p->row_status = RowStatus_active; 817 return (ret); 818} 819 820/** 821 * Close an IPv6 socket. Keep the sock object. 822 * 823 * \param p inet port 824 */ 825static void 826ipv6_deactivate(struct inet_port *p) 827{ 828 struct port_sock *sock = TAILQ_FIRST(&p->socks); 829 assert(sock); 830 assert(!TAILQ_NEXT(sock, link)); 831 832 snmpd_input_close(&sock->input); 833 834 p->row_status = RowStatus_notInService; 835} 836 837/** 838 * IPv6 specific part of message processing. The control data may contain 839 * credentials and packet info that contains the destination address of 840 * the packet. 841 * 842 * \param sock the sock object 843 * \param msg the received message 844 */ 845static void 846ipv6_parse_ctrl(struct port_sock *sock, const struct msghdr *msg) 847{ 848 struct sockcred *cred = NULL; 849 850 for (struct cmsghdr *cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; 851 cmsg = CMSG_NXTHDR(msg, cmsg)) { 852 853 if (cmsg->cmsg_level == IPPROTO_IPV6 && 854 cmsg->cmsg_type == IPV6_PKTINFO) { 855 const struct in6_pktinfo *info = 856 (const struct in6_pktinfo *)(const void *) 857 CMSG_DATA(cmsg); 858 sock->ret_source.a6.ipi6_addr = info->ipi6_addr; 859 sock->ret_source.a6.ipi6_ifindex = 860 !IN6_IS_ADDR_LINKLOCAL(&info->ipi6_addr) ? 0: 861 info->ipi6_ifindex; 862 } else if (cmsg->cmsg_level == SOL_SOCKET && 863 cmsg->cmsg_type == SCM_CREDS) { 864 cred = (struct sockcred *)(void *)CMSG_DATA(cmsg); 865 } 866 } 867 868 sock->input.priv = 0; 869 if (sock->input.cred && cred) 870 /* remote end has sent credentials */ 871 sock->input.priv = (cred->sc_euid == 0); 872} 873 874/** 875 * Set the source address option for IPv4 sockets. 876 * 877 * \param sock socket object 878 * \param msg message 879 */ 880static void 881ipv6_setsrc(struct port_sock *sock, struct msghdr *msg, char *cbuf) 882{ 883 struct cmsghdr *cmsg; 884 885 msg->msg_control = cbuf; 886 msg->msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)); 887 888 /* select outgoing interface by setting source address */ 889 cmsg = CMSG_FIRSTHDR(msg); 890 cmsg->cmsg_level = IPPROTO_IPV6; 891 cmsg->cmsg_type = IPV6_PKTINFO; 892 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); 893 memcpy(CMSG_DATA(cmsg), &sock->ret_source.a6, 894 sizeof(struct in6_pktinfo)); 895} 896 897/** 898 * IPv6z creation stuff. Parse the index, fill socket address and creates 899 * a port_sock. 900 * 901 * \param port the port to create 902 * \param params parameters from the SNMP SET 903 * 904 * \return SNMP error 905 */ 906static int 907ipv6z_create(struct inet_port *port, struct inet_port_params *params) 908{ 909 if (params->addr_len != 20) 910 return (SNMP_ERR_INCONS_VALUE); 911 912 u_int scope_id = 0; 913 for (u_int i = 16; i < 20; i++) { 914 scope_id <<= 8; 915 scope_id |= params->addr[i]; 916 } 917 918 const int ret = ipv6_create_common(port, params, scope_id); 919 if (ret != SNMP_ERR_NOERROR) 920 return (ret); 921 922 return (SNMP_ERR_NOERROR); 923} 924 925/** 926 * DNS name creation stuff. Parse the index and save the string. 927 * This does not create a socket struct. 928 * 929 * \param port the port to create 930 * \param params parameters from the SNMP SET 931 * 932 * \return SNMP error 933 */ 934static int 935dns_create(struct inet_port *port, struct inet_port_params *params) 936{ 937 if (params->addr_len > 64) 938 return (SNMP_ERR_INCONS_VALUE); 939 940 if (strnlen(params->addr, params->addr_len) != 941 params->addr_len) 942 return (SNMP_ERR_INCONS_VALUE); 943 944 if ((port->dns_addr = realloc(params->addr, 945 params->addr_len + 1)) == NULL) 946 return (SNMP_ERR_GENERR); 947 948 port->dns_addr[params->addr_len] = '\0'; 949 params->addr = NULL; 950 951 port->dns_port = htons(params->port); 952 953 return (SNMP_ERR_NOERROR); 954} 955 956/** 957 * Open sockets. This loops through all the addresses returned by getaddrinfo 958 * and opens a socket for each of them. 959 * 960 * \param port inet port 961 * 962 * \return SNMP error code 963 */ 964static int 965dns_activate(struct inet_port *port) 966{ 967 struct addrinfo hints; 968 memset(&hints, 0, sizeof(hints)); 969 hints.ai_family = AF_UNSPEC; 970 hints.ai_socktype = SOCK_DGRAM; // XXX udp-only 971 hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE | AI_NUMERICSERV; 972 973 char portbuf[8]; 974 sprintf(portbuf, "%hu", ntohs(port->dns_port)); 975 976 struct addrinfo *res0; 977 int error = getaddrinfo(port->dns_addr[0] == '\0' 978 ? NULL : port->dns_addr, 979 portbuf, &hints, &res0); 980 981 if (error) { 982 syslog(LOG_ERR, "cannot resolve address '%s': %s", 983 port->dns_addr, gai_strerror(error)); 984 return (SNMP_ERR_GENERR); 985 } 986 987 for (struct addrinfo *res = res0; res != NULL; res = res->ai_next) { 988 if (res->ai_family != AF_INET && res->ai_family != AF_INET6) 989 continue; 990 991 struct port_sock *sock = calloc(1, sizeof(struct port_sock)); 992 if (sock == NULL) 993 return (SNMP_ERR_GENERR); 994 995 snmpd_input_init(&sock->input); 996 sock->port = port; 997 998 int ret = SNMP_ERR_NOERROR; 999 1000 if (res->ai_family == AF_INET) { 1001 *(struct sockaddr_in *)&sock->bind_addr = 1002 *(struct sockaddr_in *)(void *)res->ai_addr; 1003 ret = ipv4_activate_sock(sock); 1004 } else { 1005 *(struct sockaddr_in6 *)&sock->bind_addr = 1006 *(struct sockaddr_in6 *)(void *)res->ai_addr; 1007 ret = ipv6_activate_sock(sock); 1008 } 1009 1010 if (ret != SNMP_ERR_NOERROR) 1011 free(sock); 1012 else 1013 TAILQ_INSERT_HEAD(&port->socks, sock, link); 1014 } 1015 1016 if (!TAILQ_EMPTY(&port->socks)) 1017 port->row_status = RowStatus_active; 1018 1019 freeaddrinfo(res0); 1020 return (SNMP_ERR_GENERR); 1021} 1022 1023/** 1024 * Deactive the socket. Close all open sockets and delete all sock objects. 1025 * 1026 * \param port inet port 1027 */ 1028static void 1029dns_deactivate(struct inet_port *port) 1030{ 1031 while (!TAILQ_EMPTY(&port->socks)) { 1032 struct port_sock *sock = TAILQ_FIRST(&port->socks); 1033 TAILQ_REMOVE(&port->socks, sock, link); 1034 snmpd_input_close(&sock->input); 1035 free(sock); 1036 } 1037 port->row_status = RowStatus_notInService; 1038} 1039 1040static int 1041inet_create(struct inet_port_params *params, struct inet_port **pp) 1042{ 1043 int err = SNMP_ERR_NOERROR; 1044 struct inet_port *port = NULL; 1045 1046 if (params->port > 0xffff) { 1047 err = SNMP_ERR_NO_CREATION; 1048 goto fail; 1049 } 1050 1051 if ((port = malloc(sizeof(*port))) == NULL) { 1052 err = SNMP_ERR_GENERR; 1053 goto fail; 1054 } 1055 memset(port, 0, sizeof(*port)); 1056 TAILQ_INIT(&port->socks); 1057 1058 port->proto = params->proto; 1059 port->tport.index = params->index; 1060 1061 switch (params->type) { 1062 1063 case InetAddressType_ipv4: 1064 port->create = ipv4_create; 1065 port->activate = ipv4_activate; 1066 port->deactivate = ipv4_deactivate; 1067 break; 1068 1069 case InetAddressType_ipv6: 1070 port->create = ipv6_create; 1071 port->activate = ipv6_activate; 1072 port->deactivate = ipv6_deactivate; 1073 break; 1074 1075 case InetAddressType_ipv6z: 1076 port->create = ipv6z_create; 1077 port->activate = ipv6_activate; 1078 port->deactivate = ipv6_deactivate; 1079 break; 1080 1081 case InetAddressType_dns: 1082 port->create = dns_create; 1083 port->activate = dns_activate; 1084 port->deactivate = dns_deactivate; 1085 break; 1086 1087 default: 1088 err = SNMP_ERR_NO_CREATION; 1089 goto fail; 1090 } 1091 1092 if ((err = port->create(port, params)) != SNMP_ERR_NOERROR) 1093 goto fail; 1094 1095 *pp = port; 1096 trans_insert_port(my_trans, &port->tport); 1097 return (err); 1098 1099fail: 1100 free(port->dns_addr); 1101 free(port); 1102 return (err); 1103} 1104 1105static int 1106create_and_go(struct snmp_context *ctx, struct inet_port_params *params) 1107{ 1108 int err; 1109 struct inet_port *port; 1110 1111 if ((err = inet_create(params, &port)) != SNMP_ERR_NOERROR) 1112 return (err); 1113 1114 port->row_status = RowStatus_createAndGo; 1115 ctx->scratch->ptr1 = port; 1116 1117 if (community == COMM_INITIALIZE) 1118 return (err); 1119 1120 return (inet_activate(&port->tport)); 1121} 1122 1123static int 1124create_and_wait(struct snmp_context *ctx, struct inet_port_params *params) 1125{ 1126 int err; 1127 struct inet_port *port; 1128 1129 if ((err = inet_create(params, &port)) != SNMP_ERR_NOERROR) 1130 return (err); 1131 1132 port->row_status = RowStatus_createAndWait; 1133 ctx->scratch->ptr1 = port; 1134 1135 return (err); 1136} 1137 1138/** 1139 * This is called to set a RowStatus value in the port table during 1140 * SET processing. 1141 * 1142 * When this is called during initialization time and the RowStatus is set 1143 * to CreateAndGo, the port is actually not activated. This is done when 1144 * the main code calls the init() for all ports later. 1145 */ 1146static int 1147inet_port_set(struct snmp_context *ctx, struct inet_port *port, 1148 struct inet_port_params *params, enum RowStatus nstatus) 1149{ 1150 switch (nstatus) { 1151 1152 case RowStatus_createAndGo: 1153 if (port != NULL) 1154 return (SNMP_ERR_INCONS_VALUE); 1155 ctx->scratch->int1 = SET_CREATED; 1156 return (create_and_go(ctx, params)); 1157 1158 case RowStatus_createAndWait: 1159 if (port != NULL) 1160 return (SNMP_ERR_INCONS_VALUE); 1161 ctx->scratch->int1 = SET_CREATED; 1162 return (create_and_wait(ctx, params)); 1163 1164 case RowStatus_active: 1165 if (port == NULL) 1166 return (SNMP_ERR_INCONS_VALUE); 1167 1168 switch (port->row_status) { 1169 1170 case RowStatus_notReady: 1171 /* this can not happend */ 1172 abort(); 1173 1174 case RowStatus_notInService: 1175 ctx->scratch->int1 = SET_ACTIVATED; 1176 return (inet_activate(&port->tport)); 1177 1178 case RowStatus_active: 1179 return (SNMP_ERR_NOERROR); 1180 1181 case RowStatus_createAndGo: 1182 case RowStatus_createAndWait: 1183 case RowStatus_destroy: 1184 abort(); 1185 } 1186 break; 1187 1188 case RowStatus_notInService: 1189 if (port == NULL) 1190 return (SNMP_ERR_INCONS_VALUE); 1191 1192 switch (port->row_status) { 1193 1194 case RowStatus_notReady: 1195 /* this can not happend */ 1196 abort(); 1197 1198 case RowStatus_notInService: 1199 return (SNMP_ERR_NOERROR); 1200 1201 case RowStatus_active: 1202 /* this is done during commit */ 1203 ctx->scratch->int1 = SET_DEACTIVATE; 1204 return (SNMP_ERR_NOERROR); 1205 1206 case RowStatus_createAndGo: 1207 case RowStatus_createAndWait: 1208 case RowStatus_destroy: 1209 abort(); 1210 } 1211 break; 1212 1213 case RowStatus_destroy: 1214 /* this is done during commit */ 1215 ctx->scratch->int1 = SET_DESTROY; 1216 return (SNMP_ERR_NOERROR); 1217 1218 case RowStatus_notReady: 1219 return (SNMP_ERR_WRONG_VALUE); 1220 } 1221 abort(); 1222} 1223 1224/* 1225 * Port table 1226 */ 1227int 1228op_snmp_trans_inet(struct snmp_context *ctx, struct snmp_value *value, 1229 u_int sub, u_int iidx __unused, enum snmp_op op) 1230{ 1231 asn_subid_t which = value->var.subs[sub - 1]; 1232 struct inet_port *port; 1233 struct inet_port_params params; 1234 int ret; 1235 1236 switch (op) { 1237 1238 case SNMP_OP_GETNEXT: 1239 if ((port = (struct inet_port *)trans_next_port(my_trans, 1240 &value->var, sub)) == NULL) 1241 return (SNMP_ERR_NOSUCHNAME); 1242 index_append(&value->var, sub, &port->tport.index); 1243 goto fetch; 1244 1245 case SNMP_OP_GET: 1246 if ((port = (struct inet_port *)trans_find_port(my_trans, 1247 &value->var, sub)) == NULL) 1248 return (SNMP_ERR_NOSUCHNAME); 1249 goto fetch; 1250 1251 case SNMP_OP_SET: 1252 port = (struct inet_port *)trans_find_port(my_trans, 1253 &value->var, sub); 1254 1255 if (which != LEAF_begemotSnmpdTransInetStatus) 1256 abort(); 1257 if (!isok_RowStatus(value->v.integer)) 1258 return (SNMP_ERR_WRONG_VALUE); 1259 1260 if (index_decode(&value->var, sub, iidx, ¶ms.type, 1261 ¶ms.addr, ¶ms.addr_len, ¶ms.port, 1262 ¶ms.proto)) 1263 return (SNMP_ERR_NO_CREATION); 1264 1265 asn_slice_oid(¶ms.index, &value->var, sub, value->var.len); 1266 1267 ret = inet_port_set(ctx, port, ¶ms, 1268 (enum RowStatus)value->v.integer); 1269 1270 free(params.addr); 1271 return (ret); 1272 1273 case SNMP_OP_ROLLBACK: 1274 if ((port = (struct inet_port *)trans_find_port(my_trans, 1275 &value->var, sub)) == NULL) 1276 /* cannot happen */ 1277 abort(); 1278 1279 switch (ctx->scratch->int1) { 1280 1281 case SET_CREATED: 1282 /* newly created */ 1283 assert(port != NULL); 1284 inet_destroy_port(&port->tport); 1285 return (SNMP_ERR_NOERROR); 1286 1287 case SET_DESTROY: 1288 /* do it now */ 1289 assert(port != NULL); 1290 return (SNMP_ERR_NOERROR); 1291 1292 case SET_ACTIVATED: 1293 deactivate_port(port); 1294 return (SNMP_ERR_NOERROR); 1295 1296 case SET_DEACTIVATE: 1297 return (SNMP_ERR_NOERROR); 1298 } 1299 abort(); 1300 1301 case SNMP_OP_COMMIT: 1302 if ((port = (struct inet_port *)trans_find_port(my_trans, 1303 &value->var, sub)) == NULL) 1304 /* cannot happen */ 1305 abort(); 1306 1307 switch (ctx->scratch->int1) { 1308 1309 case SET_CREATED: 1310 /* newly created */ 1311 assert(port != NULL); 1312 return (SNMP_ERR_NOERROR); 1313 1314 case SET_DESTROY: 1315 /* do it now */ 1316 assert(port != NULL); 1317 inet_destroy_port(&port->tport); 1318 return (SNMP_ERR_NOERROR); 1319 1320 case SET_ACTIVATED: 1321 return (SNMP_ERR_NOERROR); 1322 1323 case SET_DEACTIVATE: 1324 deactivate_port(port); 1325 return (SNMP_ERR_NOERROR); 1326 } 1327 abort(); 1328 } 1329 abort(); 1330 1331 fetch: 1332 switch (which) { 1333 1334 case LEAF_begemotSnmpdTransInetStatus: 1335 value->v.integer = port->row_status; 1336 break; 1337 1338 default: 1339 abort(); 1340 } 1341 1342 return (SNMP_ERR_NOERROR); 1343} 1344