6 * Author: Harti Brandt <harti@freebsd.org>
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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
29 * $Begemot: bsnmp/snmpd/trans_udp.c,v 1.5 2005/10/04 08:46:56 brandt_h Exp $
34 #include <sys/param.h>
35 #include <sys/socket.h>
36 #include <sys/types.h>
50 #include <arpa/inet.h>
58 #define SNMPTREE_TYPES
59 #define SNMPENUM_FUNCS
63 extern const struct transport_def inet_trans;
66 struct inet_port_params;
69 typedef int create_func(struct inet_port *, struct inet_port_params *);
70 typedef void input_func(int, void *);
71 typedef int activate_func(struct inet_port *);
72 typedef void deactivate_func(struct inet_port *);
73 typedef void parse_ctrl_func(struct port_sock *, const struct msghdr *);
74 typedef void setsrc_func(struct port_sock *, struct msghdr *, char *);
76 static create_func ipv4_create;
77 static input_func ipv4_input;
78 static activate_func ipv4_activate;
79 static deactivate_func ipv4_deactivate;
80 static parse_ctrl_func ipv4_parse_ctrl;
81 static setsrc_func ipv4_setsrc;
83 static create_func ipv6_create;
84 static input_func ipv6_input;
85 static activate_func ipv6_activate;
86 static deactivate_func ipv6_deactivate;
87 static parse_ctrl_func ipv6_parse_ctrl;
88 static setsrc_func ipv6_setsrc;
90 static create_func ipv6z_create;
92 static create_func dns_create;
93 static activate_func dns_activate;
94 static deactivate_func dns_deactivate;
97 /* common input stuff; must be first */
98 struct port_input input;
101 TAILQ_ENTRY(port_sock) link;
103 /** pointer to parent */
104 struct inet_port *port;
107 struct sockaddr_storage bind_addr;
109 /** reply destination */
110 struct sockaddr_storage ret_dest;
112 /** need to set source address in reply; set for INADDR_ANY */
115 /** address of the receive interface */
121 struct in6_pktinfo a6;
124 /** parse control message */
125 parse_ctrl_func *parse_ctrl;
127 /** set source address for a send() */
130 static_assert(offsetof(struct port_sock, input) == 0,
131 "input not first in port_sock");
134 * Table row for the inet ports.
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.
141 /** common i/o port stuff (must be first) */
144 /** transport protocol */
145 enum BegemotSnmpdTransportProto proto;
148 enum RowStatus row_status;
151 TAILQ_HEAD(, port_sock) socks;
153 /** value for InetAddressType::dns */
156 /** port number in dns case; network byte order */
162 /** activate a port */
163 activate_func *activate;
165 /** deactivate port */
166 deactivate_func *deactivate;
168 static_assert(offsetof(struct inet_port, tport) == 0,
169 "tport not first in inet_port");
171 /** to be used in bind_addr field */
172 #define AF_DNS AF_VENDOR00
174 /** registered transport */
175 static struct transport *my_trans;
185 /** length of the control data buffer */
186 static 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)));
192 /** length of the control data buffer */
193 static const size_t XMIT_CBUF_SIZE =
194 MAX(CMSG_SPACE(sizeof(struct in_addr)),
195 CMSG_SPACE(sizeof(struct in6_pktinfo)));
198 * Start the transport. This registers the transport with the
201 * \return SNMP error code
206 return (trans_register(&inet_trans, &my_trans));
210 * Stop the transport. This tries to unregister the transport which
211 * in turn fails if the list of ports is not empty.
213 * \return SNMP error code
216 inet_stop(int force __unused)
218 if (my_trans != NULL)
219 if (trans_unregister(my_trans) != 0)
220 return (SNMP_ERR_GENERR);
221 return (SNMP_ERR_NOERROR);
225 * Deactivate SNMP port.
227 * \param tp port to close
230 deactivate_port(struct inet_port *p)
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.
241 * \param tp transport port
243 * \return SNMP error code
246 inet_activate(struct tport *tp)
248 struct inet_port *port = (struct inet_port *)tp;
250 return (port->activate(port));
254 * Close the SNMP port if it is open and destroy it.
256 * \param tp port to close
259 inet_destroy_port(struct tport *tp)
261 struct inet_port *port = (struct inet_port *)tp;
263 deactivate_port(port);
265 trans_remove_port(tp);
267 free(port->dns_addr);
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.
275 * \param pi input struct
277 * \return -1 if allocation fails, 0 otherwise
280 inet_alloc_buf(struct port_input *pi)
284 if (pi->buf == NULL) {
285 if ((pi->buf = buf_alloc(0)) == NULL) {
286 (void)recvfrom(pi->fd, drop_buf, sizeof(drop_buf),
290 pi->buflen = buf_size(0);
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.
300 * \param pi input object
301 * \param msg message object to fill
302 * \param cbuf control data buffer
304 * \return -1 when something goes wrong, 0 othersise
307 inet_read_msg(struct port_input *pi, struct msghdr *msg, char *cbuf)
311 iov[0].iov_base = pi->buf;
312 iov[0].iov_len = pi->buflen;
314 msg->msg_name = pi->peer;
315 msg->msg_namelen = pi->peerlen;
318 msg->msg_control = cbuf;
319 msg->msg_controllen = RECV_CBUF_SIZE;
322 memset(cbuf, 0, RECV_CBUF_SIZE);
324 const ssize_t len = recvmsg(pi->fd, msg, 0);
326 if (len == -1 || len == 0)
330 if (msg->msg_flags & MSG_TRUNC) {
331 /* truncated - drop */
332 snmpd_stats.silentDrops++;
333 snmpd_stats.inTooLong++;
337 pi->length = (size_t)len;
343 * Input available on socket.
345 * \param tp transport port
346 * \param pi input struct
348 * \return number of bytes received
351 inet_recv(struct tport *tp, struct port_input *pi)
353 struct inet_port *port = __containerof(tp, struct inet_port, tport);
354 struct port_sock *sock = __containerof(pi, struct port_sock, input);
356 assert(port->proto == BegemotSnmpdTransportProto_udp);
358 if (inet_alloc_buf(pi) == -1)
361 char cbuf[RECV_CBUF_SIZE];
364 if (inet_read_msg(pi, &msg, cbuf) == -1)
367 sock->parse_ctrl(sock, &msg);
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
381 * \return number of bytes sent
384 inet_send2(struct tport *tp, const u_char *buf, size_t len,
385 struct port_input *pi)
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);
393 iov.iov_base = __DECONST(void*, buf);
401 msg.msg_name = (void *)pi->peer;
402 msg.msg_namelen = pi->peerlen;
404 char cbuf[XMIT_CBUF_SIZE];
405 if (s->set_ret_source) {
406 s->setsrc(s, &msg, cbuf);
408 msg.msg_control = NULL;
409 msg.msg_controllen = 0;
412 return (sendmsg(s->input.fd, &msg, 0));
415 /** exported to daemon */
416 const struct transport_def inet_trans = {
418 OIDX_begemotSnmpdTransInet,
428 struct inet_port_params {
430 struct asn_oid index;
432 /** internet address type */
433 enum InetAddressType type;
435 /** internet address */
438 /** length of address */
445 enum BegemotSnmpdTransportProto proto;
449 * IPv4 creation stuff. Parse the index, fill socket address and creates
452 * \param port the port to create
453 * \param params parameters from the SNMP SET
458 ipv4_create(struct inet_port *port, struct inet_port_params *params)
461 if (params->addr_len != 4)
462 return (SNMP_ERR_INCONS_VALUE);
464 struct port_sock *sock = calloc(1, sizeof(struct port_sock));
466 return (SNMP_ERR_GENERR);
468 snmpd_input_init(&sock->input);
470 TAILQ_INSERT_HEAD(&port->socks, sock, link);
472 struct sockaddr_in *sin =
473 (struct sockaddr_in *)&sock->bind_addr;
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 */
482 return (SNMP_ERR_NOERROR);
486 * An IPv4 inet port is ready. Delegate to the generic code to read the data
489 * \param fd file descriptor that is ready
490 * \param udata inet_port pointer
493 ipv4_input(int fd __unused, void *udata)
495 struct port_sock *sock = udata;
497 sock->input.peerlen = sizeof(struct sockaddr_in);
498 snmpd_input(&sock->input, &sock->port->tport);
502 * Activate an IPv4 socket.
504 * \param sock thhe socket to activate
509 ipv4_activate_sock(struct port_sock *sock)
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);
516 const struct sockaddr_in *sin =
517 (const struct sockaddr_in *)&sock->bind_addr;
519 if (sin->sin_addr.s_addr == INADDR_ANY) {
520 /* need to know from which address to return */
521 static const int on = 1;
523 if (setsockopt(sock->input.fd, IPPROTO_IP, IP_RECVDSTADDR, &on,
525 syslog(LOG_ERR, "setsockopt(IP_RECVDSTADDR): %m");
526 (void)close(sock->input.fd);
528 return (SNMP_ERR_GENERR);
530 sock->set_ret_source = true;
533 if (bind(sock->input.fd, (const struct sockaddr *)sin, sizeof(*sin))) {
534 if (errno == EADDRNOTAVAIL) {
535 (void)close(sock->input.fd);
537 return (SNMP_ERR_INCONS_NAME);
539 syslog(LOG_ERR, "bind: %s:%u %m", inet_ntoa(sin->sin_addr),
540 ntohs(sin->sin_port));
541 (void)close(sock->input.fd);
543 return (SNMP_ERR_GENERR);
546 if ((sock->input.id = fd_select(sock->input.fd, ipv4_input,
547 sock, NULL)) == NULL) {
548 (void)close(sock->input.fd);
550 return (SNMP_ERR_GENERR);
552 sock->input.peer = (struct sockaddr *)&sock->ret_dest;
554 sock->parse_ctrl = ipv4_parse_ctrl;
555 sock->setsrc = ipv4_setsrc;
557 return (SNMP_ERR_NOERROR);
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.
566 * \return SNMP error code
569 ipv4_activate(struct inet_port *p)
571 struct port_sock *sock = TAILQ_FIRST(&p->socks);
573 assert(!TAILQ_NEXT(sock, link));
575 const int ret = ipv4_activate_sock(sock);
576 if (ret == SNMP_ERR_NOERROR)
577 p->row_status = RowStatus_active;
583 * Close an IPv4 socket. Keep the sock object.
588 ipv4_deactivate(struct inet_port *p)
590 struct port_sock *sock = TAILQ_FIRST(&p->socks);
592 assert(!TAILQ_NEXT(sock, link));
594 snmpd_input_close(&sock->input);
596 p->row_status = RowStatus_notInService;
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.
605 * \param sock the sock object
606 * \param msg the received message
609 ipv4_parse_ctrl(struct port_sock *sock, const struct msghdr *msg)
611 struct sockcred *cred = NULL;
613 for (struct cmsghdr *cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL;
614 cmsg = CMSG_NXTHDR(msg, cmsg)) {
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));
621 } else if (cmsg->cmsg_level == SOL_SOCKET &&
622 cmsg->cmsg_type == SCM_CREDS) {
623 cred = (struct sockcred *)(void *)CMSG_DATA(cmsg);
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);
634 * Set the source address option for IPv4 sockets.
636 * \param sock socket object
640 ipv4_setsrc(struct port_sock *sock, struct msghdr *msg, char *cbuf)
642 struct cmsghdr *cmsg;
644 msg->msg_control = cbuf;
645 msg->msg_controllen = CMSG_SPACE(sizeof(struct in_addr));
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));
657 * Common part of IPv6 creation. This is used by both ipv6_create() and
660 * \param port the table row
661 * \param params creation parameters
662 * \param scope_id scope_id (0 or from index)
664 * \return SNMP_ERR_NOERROR if port has been created, error code otherwise
667 ipv6_create_common(struct inet_port *port, struct inet_port_params *params,
670 struct port_sock *sock = calloc(1, sizeof(struct port_sock));
673 return (SNMP_ERR_GENERR);
675 struct sockaddr_in6 *sin = (struct sockaddr_in6 *)&sock->bind_addr;
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;
683 memcpy(sin->sin6_addr.s6_addr, params->addr, 16);
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)));
691 return (SNMP_ERR_NO_CREATION);
696 snmpd_input_init(&sock->input);
697 TAILQ_INSERT_HEAD(&port->socks, sock, link);
699 return (SNMP_ERR_NOERROR);
703 * IPv6 creation stuff. Parse the index, fill socket address and creates
706 * \param port the port to create
707 * \param params parameters from the SNMP SET
712 ipv6_create(struct inet_port *port, struct inet_port_params *params)
714 if (params->addr_len != 16)
715 return (SNMP_ERR_INCONS_VALUE);
717 const int ret = ipv6_create_common(port, params, 0);
718 if (ret != SNMP_ERR_NOERROR)
721 return (SNMP_ERR_NOERROR);
725 * An IPv6 inet port is ready. Delegate to the generic code to read the data
728 * \param fd file descriptor that is ready
729 * \param udata inet_port pointer
732 ipv6_input(int fd __unused, void *udata)
734 struct port_sock *sock = udata;
736 sock->input.peerlen = sizeof(struct sockaddr_in6);
737 snmpd_input(&sock->input, &sock->port->tport);
741 * Activate an IPv6 socket.
743 * \param sock thhe socket to activate
748 ipv6_activate_sock(struct port_sock *sock)
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);
755 const struct sockaddr_in6 *sin =
756 (const struct sockaddr_in6 *)&sock->bind_addr;
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;
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);
767 return (SNMP_ERR_GENERR);
769 sock->set_ret_source = true;
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);
776 return (SNMP_ERR_INCONS_NAME);
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);
784 return (SNMP_ERR_GENERR);
786 if ((sock->input.id = fd_select(sock->input.fd, ipv6_input,
787 sock, NULL)) == NULL) {
788 (void)close(sock->input.fd);
790 return (SNMP_ERR_GENERR);
792 sock->input.peer = (struct sockaddr *)&sock->ret_dest;
794 sock->parse_ctrl = ipv6_parse_ctrl;
795 sock->setsrc = ipv6_setsrc;
797 return (SNMP_ERR_NOERROR);
801 * Open an IPv6 socket.
803 * \param port inet port
805 * \return SNMP error code
808 ipv6_activate(struct inet_port *p)
810 struct port_sock *sock = TAILQ_FIRST(&p->socks);
813 const int ret = ipv6_activate_sock(sock);
815 if (ret == SNMP_ERR_NOERROR)
816 p->row_status = RowStatus_active;
821 * Close an IPv6 socket. Keep the sock object.
826 ipv6_deactivate(struct inet_port *p)
828 struct port_sock *sock = TAILQ_FIRST(&p->socks);
830 assert(!TAILQ_NEXT(sock, link));
832 snmpd_input_close(&sock->input);
834 p->row_status = RowStatus_notInService;
838 * IPv6 specific part of message processing. The control data may contain
839 * credentials and packet info that contains the destination address of
842 * \param sock the sock object
843 * \param msg the received message
846 ipv6_parse_ctrl(struct port_sock *sock, const struct msghdr *msg)
848 struct sockcred *cred = NULL;
850 for (struct cmsghdr *cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL;
851 cmsg = CMSG_NXTHDR(msg, cmsg)) {
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 *)
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:
863 } else if (cmsg->cmsg_level == SOL_SOCKET &&
864 cmsg->cmsg_type == SCM_CREDS) {
865 cred = (struct sockcred *)(void *)CMSG_DATA(cmsg);
869 sock->input.priv = 0;
870 if (sock->input.cred && cred)
871 /* remote end has sent credentials */
872 sock->input.priv = (cred->sc_euid == 0);
876 * Set the source address option for IPv4 sockets.
878 * \param sock socket object
882 ipv6_setsrc(struct port_sock *sock, struct msghdr *msg, char *cbuf)
884 struct cmsghdr *cmsg;
886 msg->msg_control = cbuf;
887 msg->msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
889 /* select outgoing interface by setting source address */
890 cmsg = CMSG_FIRSTHDR(msg);
891 cmsg->cmsg_level = IPPROTO_IPV6;
892 cmsg->cmsg_type = IPV6_PKTINFO;
893 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
894 memcpy(CMSG_DATA(cmsg), &sock->ret_source.a6,
895 sizeof(struct in6_pktinfo));
899 * IPv6z creation stuff. Parse the index, fill socket address and creates
902 * \param port the port to create
903 * \param params parameters from the SNMP SET
908 ipv6z_create(struct inet_port *port, struct inet_port_params *params)
910 if (params->addr_len != 20)
911 return (SNMP_ERR_INCONS_VALUE);
914 for (u_int i = 16; i < 20; i++) {
916 scope_id |= params->addr[i];
919 const int ret = ipv6_create_common(port, params, scope_id);
920 if (ret != SNMP_ERR_NOERROR)
923 return (SNMP_ERR_NOERROR);
927 * DNS name creation stuff. Parse the index and save the string.
928 * This does not create a socket struct.
930 * \param port the port to create
931 * \param params parameters from the SNMP SET
936 dns_create(struct inet_port *port, struct inet_port_params *params)
938 if (params->addr_len > 64)
939 return (SNMP_ERR_INCONS_VALUE);
941 if (strnlen(params->addr, params->addr_len) !=
943 return (SNMP_ERR_INCONS_VALUE);
945 if ((port->dns_addr = realloc(params->addr,
946 params->addr_len + 1)) == NULL)
947 return (SNMP_ERR_GENERR);
949 port->dns_addr[params->addr_len] = '\0';
952 port->dns_port = htons(params->port);
954 return (SNMP_ERR_NOERROR);
958 * Open sockets. This loops through all the addresses returned by getaddrinfo
959 * and opens a socket for each of them.
961 * \param port inet port
963 * \return SNMP error code
966 dns_activate(struct inet_port *port)
968 struct addrinfo hints;
969 memset(&hints, 0, sizeof(hints));
970 hints.ai_family = AF_UNSPEC;
971 hints.ai_socktype = SOCK_DGRAM; // XXX udp-only
972 hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE | AI_NUMERICSERV;
975 sprintf(portbuf, "%hu", ntohs(port->dns_port));
977 struct addrinfo *res0;
978 int error = getaddrinfo(port->dns_addr[0] == '\0'
979 ? NULL : port->dns_addr,
980 portbuf, &hints, &res0);
983 syslog(LOG_ERR, "cannot resolve address '%s': %s",
984 port->dns_addr, gai_strerror(error));
985 return (SNMP_ERR_GENERR);
988 for (struct addrinfo *res = res0; res != NULL; res = res->ai_next) {
989 if (res->ai_family != AF_INET && res->ai_family != AF_INET6)
992 struct port_sock *sock = calloc(1, sizeof(struct port_sock));
994 return (SNMP_ERR_GENERR);
996 snmpd_input_init(&sock->input);
999 int ret = SNMP_ERR_NOERROR;
1001 if (res->ai_family == AF_INET) {
1002 *(struct sockaddr_in *)&sock->bind_addr =
1003 *(struct sockaddr_in *)(void *)res->ai_addr;
1004 ret = ipv4_activate_sock(sock);
1006 *(struct sockaddr_in6 *)&sock->bind_addr =
1007 *(struct sockaddr_in6 *)(void *)res->ai_addr;
1008 ret = ipv6_activate_sock(sock);
1011 if (ret != SNMP_ERR_NOERROR)
1014 TAILQ_INSERT_HEAD(&port->socks, sock, link);
1017 if (!TAILQ_EMPTY(&port->socks))
1018 port->row_status = RowStatus_active;
1021 return (SNMP_ERR_GENERR);
1025 * Deactive the socket. Close all open sockets and delete all sock objects.
1027 * \param port inet port
1030 dns_deactivate(struct inet_port *port)
1032 while (!TAILQ_EMPTY(&port->socks)) {
1033 struct port_sock *sock = TAILQ_FIRST(&port->socks);
1034 TAILQ_REMOVE(&port->socks, sock, link);
1035 snmpd_input_close(&sock->input);
1038 port->row_status = RowStatus_notInService;
1042 inet_create(struct inet_port_params *params, struct inet_port **pp)
1044 int err = SNMP_ERR_NOERROR;
1045 struct inet_port *port = NULL;
1047 if (params->port > 0xffff) {
1048 err = SNMP_ERR_NO_CREATION;
1052 if ((port = malloc(sizeof(*port))) == NULL) {
1053 err = SNMP_ERR_GENERR;
1056 memset(port, 0, sizeof(*port));
1057 TAILQ_INIT(&port->socks);
1059 port->proto = params->proto;
1060 port->tport.index = params->index;
1062 switch (params->type) {
1064 case InetAddressType_ipv4:
1065 port->create = ipv4_create;
1066 port->activate = ipv4_activate;
1067 port->deactivate = ipv4_deactivate;
1070 case InetAddressType_ipv6:
1071 port->create = ipv6_create;
1072 port->activate = ipv6_activate;
1073 port->deactivate = ipv6_deactivate;
1076 case InetAddressType_ipv6z:
1077 port->create = ipv6z_create;
1078 port->activate = ipv6_activate;
1079 port->deactivate = ipv6_deactivate;
1082 case InetAddressType_dns:
1083 port->create = dns_create;
1084 port->activate = dns_activate;
1085 port->deactivate = dns_deactivate;
1089 err = SNMP_ERR_NO_CREATION;
1093 if ((err = port->create(port, params)) != SNMP_ERR_NOERROR)
1097 trans_insert_port(my_trans, &port->tport);
1101 free(port->dns_addr);
1107 create_and_go(struct snmp_context *ctx, struct inet_port_params *params)
1110 struct inet_port *port;
1112 if ((err = inet_create(params, &port)) != SNMP_ERR_NOERROR)
1115 port->row_status = RowStatus_createAndGo;
1116 ctx->scratch->ptr1 = port;
1118 if (community == COMM_INITIALIZE)
1121 return (inet_activate(&port->tport));
1125 create_and_wait(struct snmp_context *ctx, struct inet_port_params *params)
1128 struct inet_port *port;
1130 if ((err = inet_create(params, &port)) != SNMP_ERR_NOERROR)
1133 port->row_status = RowStatus_createAndWait;
1134 ctx->scratch->ptr1 = port;
1140 * This is called to set a RowStatus value in the port table during
1143 * When this is called during initialization time and the RowStatus is set
1144 * to CreateAndGo, the port is actually not activated. This is done when
1145 * the main code calls the init() for all ports later.
1148 inet_port_set(struct snmp_context *ctx, struct inet_port *port,
1149 struct inet_port_params *params, enum RowStatus nstatus)
1153 case RowStatus_createAndGo:
1155 return (SNMP_ERR_INCONS_VALUE);
1156 ctx->scratch->int1 = SET_CREATED;
1157 return (create_and_go(ctx, params));
1159 case RowStatus_createAndWait:
1161 return (SNMP_ERR_INCONS_VALUE);
1162 ctx->scratch->int1 = SET_CREATED;
1163 return (create_and_wait(ctx, params));
1165 case RowStatus_active:
1167 return (SNMP_ERR_INCONS_VALUE);
1169 switch (port->row_status) {
1171 case RowStatus_notReady:
1172 /* this can not happend */
1175 case RowStatus_notInService:
1176 ctx->scratch->int1 = SET_ACTIVATED;
1177 return (inet_activate(&port->tport));
1179 case RowStatus_active:
1180 return (SNMP_ERR_NOERROR);
1182 case RowStatus_createAndGo:
1183 case RowStatus_createAndWait:
1184 case RowStatus_destroy:
1189 case RowStatus_notInService:
1191 return (SNMP_ERR_INCONS_VALUE);
1193 switch (port->row_status) {
1195 case RowStatus_notReady:
1196 /* this can not happend */
1199 case RowStatus_notInService:
1200 return (SNMP_ERR_NOERROR);
1202 case RowStatus_active:
1203 /* this is done during commit */
1204 ctx->scratch->int1 = SET_DEACTIVATE;
1205 return (SNMP_ERR_NOERROR);
1207 case RowStatus_createAndGo:
1208 case RowStatus_createAndWait:
1209 case RowStatus_destroy:
1214 case RowStatus_destroy:
1215 /* this is done during commit */
1216 ctx->scratch->int1 = SET_DESTROY;
1217 return (SNMP_ERR_NOERROR);
1219 case RowStatus_notReady:
1220 return (SNMP_ERR_WRONG_VALUE);
1229 op_snmp_trans_inet(struct snmp_context *ctx, struct snmp_value *value,
1230 u_int sub, u_int iidx __unused, enum snmp_op op)
1232 asn_subid_t which = value->var.subs[sub - 1];
1233 struct inet_port *port;
1234 struct inet_port_params params;
1239 case SNMP_OP_GETNEXT:
1240 if ((port = (struct inet_port *)trans_next_port(my_trans,
1241 &value->var, sub)) == NULL)
1242 return (SNMP_ERR_NOSUCHNAME);
1243 index_append(&value->var, sub, &port->tport.index);
1247 if ((port = (struct inet_port *)trans_find_port(my_trans,
1248 &value->var, sub)) == NULL)
1249 return (SNMP_ERR_NOSUCHNAME);
1253 port = (struct inet_port *)trans_find_port(my_trans,
1256 if (which != LEAF_begemotSnmpdTransInetStatus)
1258 if (!isok_RowStatus(value->v.integer))
1259 return (SNMP_ERR_WRONG_VALUE);
1261 if (index_decode(&value->var, sub, iidx, ¶ms.type,
1262 ¶ms.addr, ¶ms.addr_len, ¶ms.port,
1264 return (SNMP_ERR_NO_CREATION);
1266 asn_slice_oid(¶ms.index, &value->var, sub, value->var.len);
1268 ret = inet_port_set(ctx, port, ¶ms,
1269 (enum RowStatus)value->v.integer);
1274 case SNMP_OP_ROLLBACK:
1275 if ((port = (struct inet_port *)trans_find_port(my_trans,
1276 &value->var, sub)) == NULL)
1280 switch (ctx->scratch->int1) {
1284 assert(port != NULL);
1285 inet_destroy_port(&port->tport);
1286 return (SNMP_ERR_NOERROR);
1290 assert(port != NULL);
1291 return (SNMP_ERR_NOERROR);
1294 deactivate_port(port);
1295 return (SNMP_ERR_NOERROR);
1297 case SET_DEACTIVATE:
1298 return (SNMP_ERR_NOERROR);
1302 case SNMP_OP_COMMIT:
1303 if ((port = (struct inet_port *)trans_find_port(my_trans,
1304 &value->var, sub)) == NULL)
1308 switch (ctx->scratch->int1) {
1312 assert(port != NULL);
1313 return (SNMP_ERR_NOERROR);
1317 assert(port != NULL);
1318 inet_destroy_port(&port->tport);
1319 return (SNMP_ERR_NOERROR);
1322 return (SNMP_ERR_NOERROR);
1324 case SET_DEACTIVATE:
1325 deactivate_port(port);
1326 return (SNMP_ERR_NOERROR);
1335 case LEAF_begemotSnmpdTransInetStatus:
1336 value->v.integer = port->row_status;
1343 return (SNMP_ERR_NOERROR);