1 // SPDX-License-Identifier: ISC
5 * Copyright (c) 2016 Renato Westphal <renato@openbsd.org>
6 * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
7 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
8 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
21 extern struct zebra_privs_t ldpd_privs
;
22 extern struct zebra_privs_t ldpe_privs
;
25 ldp_create_socket(int af
, enum socket_type type
)
27 int fd
, domain
, proto
;
29 union sockunion local_su
;
37 case LDP_SOCKET_EDISC
:
41 case LDP_SOCKET_SESSION
:
46 fatalx("ldp_create_socket: unknown socket type");
48 fd
= socket(af
, domain
, proto
);
50 log_warn("%s: error creating socket", __func__
);
53 sock_set_nonblock(fd
);
54 sockopt_v6only(af
, fd
);
56 /* bind to a local address/port */
59 /* listen on all addresses */
60 memset(&addr
, 0, sizeof(addr
));
61 addr2sa(af
, &addr
, LDP_PORT
, &local_su
);
63 case LDP_SOCKET_EDISC
:
64 case LDP_SOCKET_SESSION
:
65 addr
= (ldp_af_conf_get(ldpd_conf
, af
))->trans_addr
;
66 addr2sa(af
, &addr
, LDP_PORT
, &local_su
);
67 /* ignore any possible error */
68 sock_set_bindany(fd
, 1);
71 frr_with_privs(&ldpd_privs
) {
72 if (sock_set_reuse(fd
, 1) == -1) {
76 if (bind(fd
, &local_su
.sa
, sockaddr_len(&local_su
.sa
)) == -1) {
77 log_warnx("%s: error binding socket: %s", __func__
,
78 safe_strerror(errno
));
87 if (sock_set_ipv4_tos(fd
, IPTOS_PREC_INTERNETCONTROL
) == -1) {
91 if (type
== LDP_SOCKET_DISC
) {
92 if (sock_set_ipv4_mcast_ttl(fd
, IP_DEFAULT_MULTICAST_TTL
) == -1) {
96 if (sock_set_ipv4_mcast_loop(fd
) == -1) {
101 if (type
== LDP_SOCKET_DISC
|| type
== LDP_SOCKET_EDISC
) {
102 if (sock_set_ipv4_recvif(fd
, 1) == -1) {
107 #if defined(HAVE_IP_PKTINFO)
108 if (sock_set_ipv4_pktinfo(fd
, 1) == -1) {
112 #elif defined(HAVE_IP_RECVDSTADDR)
113 if (sock_set_ipv4_recvdstaddr(fd
, 1) == -1) {
118 #error "Unsupported socket API"
120 #endif /* MSG_MCAST */
122 if (type
== LDP_SOCKET_SESSION
) {
123 if (sock_set_ipv4_ucast_ttl(fd
, 255) == -1) {
130 if (sock_set_ipv6_dscp(fd
, IPTOS_PREC_INTERNETCONTROL
) == -1) {
134 if (type
== LDP_SOCKET_DISC
) {
135 if (sock_set_ipv6_mcast_loop(fd
) == -1) {
139 if (sock_set_ipv6_mcast_hops(fd
, 255) == -1) {
143 if (!CHECK_FLAG(ldpd_conf
->ipv6
.flags
, F_LDPD_AF_NO_GTSM
)) {
144 /* ignore any possible error */
145 sock_set_ipv6_minhopcount(fd
, 255);
148 if (type
== LDP_SOCKET_DISC
|| type
== LDP_SOCKET_EDISC
) {
149 if (sock_set_ipv6_pktinfo(fd
, 1) == -1) {
154 if (type
== LDP_SOCKET_SESSION
) {
155 if (sock_set_ipv6_ucast_hops(fd
, 255) == -1) {
163 case LDP_SOCKET_DISC
:
164 case LDP_SOCKET_EDISC
:
165 sock_set_recvbuf(fd
);
167 case LDP_SOCKET_SESSION
:
168 if (listen(fd
, LDP_BACKLOG
) == -1)
169 log_warn("%s: error listening on socket", __func__
);
173 if (setsockopt(fd
, IPPROTO_TCP
, TCP_MD5SIG
, &opt
, sizeof(opt
)) == -1) {
174 if (errno
== ENOPROTOOPT
) { /* system w/o md5sig */
175 log_warnx("md5sig not available, disabling");
176 sysdep
.no_md5sig
= 1;
190 sock_set_nonblock(int fd
)
194 if ((flags
= fcntl(fd
, F_GETFL
, 0)) == -1)
195 fatal("fcntl F_GETFL");
197 SET_FLAG(flags
, O_NONBLOCK
);
199 if (fcntl(fd
, F_SETFL
, flags
) == -1)
200 fatal("fcntl F_SETFL");
204 sock_set_cloexec(int fd
)
208 if ((flags
= fcntl(fd
, F_GETFD
, 0)) == -1)
209 fatal("fcntl F_GETFD");
211 SET_FLAG(flags
, FD_CLOEXEC
);
213 if (fcntl(fd
, F_SETFD
, flags
) == -1)
214 fatal("fcntl F_SETFD");
218 sock_set_recvbuf(int fd
)
223 while (setsockopt(fd
, SOL_SOCKET
, SO_RCVBUF
, &bsize
, sizeof(bsize
)) == -1)
228 sock_set_reuse(int fd
, int enable
)
230 if (setsockopt(fd
, SOL_SOCKET
, SO_REUSEADDR
, &enable
, sizeof(int)) < 0) {
231 log_warn("%s: error setting SO_REUSEADDR", __func__
);
239 sock_set_bindany(int fd
, int enable
)
241 #ifdef HAVE_SO_BINDANY
242 frr_with_privs(&ldpd_privs
) {
243 if (setsockopt(fd
, SOL_SOCKET
, SO_BINDANY
, &enable
, sizeof(int)) < 0) {
244 log_warn("%s: error setting SO_BINDANY", __func__
);
249 #elif defined(HAVE_IP_FREEBIND)
250 if (setsockopt(fd
, IPPROTO_IP
, IP_FREEBIND
, &enable
, sizeof(int)) < 0) {
251 log_warn("%s: error setting IP_FREEBIND", __func__
);
255 #elif defined(IP_BINDANY)
256 frr_with_privs(&ldpd_privs
) {
257 if (setsockopt(fd
, IPPROTO_IP
, IP_BINDANY
, &enable
, sizeof(int)) < 0) {
258 log_warn("%s: error setting IP_BINDANY", __func__
);
265 "%s: missing SO_BINDANY, IP_FREEBIND and IP_BINDANY, unable to bind to a nonlocal IP address",
268 #endif /* HAVE_SO_BINDANY */
273 * Set MD5 key for the socket, for the given peer address. If the password
274 * is NULL or zero-length, the option will be disabled.
277 sock_set_md5sig(int fd
, int af
, union ldpd_addr
*addr
, const char *password
)
280 int save_errno
= ENOSYS
;
281 #if HAVE_DECL_TCP_MD5SIG
287 #if HAVE_DECL_TCP_MD5SIG
288 addr2sa(af
, addr
, 0, &su
);
290 frr_with_privs(&ldpe_privs
) {
291 ret
= sockopt_tcp_signature(fd
, &su
, password
);
294 #endif /* HAVE_TCP_MD5SIG */
296 log_warnx("%s: can't set TCP_MD5SIG option on fd %d: %s",
297 __func__
, fd
, safe_strerror(save_errno
));
304 sock_set_ipv4_tos(int fd
, int tos
)
306 if (setsockopt(fd
, IPPROTO_IP
, IP_TOS
, &tos
, sizeof(tos
)) < 0) {
307 log_warn("%s: error setting IP_TOS to 0x%x", __func__
, tos
);
315 sock_set_ipv4_recvif(int fd
, ifindex_t enable
)
317 return (setsockopt_ifindex(AF_INET
, fd
, enable
));
321 sock_set_ipv4_minttl(int fd
, int ttl
)
323 return (sockopt_minttl(AF_INET
, fd
, ttl
));
327 sock_set_ipv4_ucast_ttl(int fd
, int ttl
)
329 if (setsockopt(fd
, IPPROTO_IP
, IP_TTL
, &ttl
, sizeof(ttl
)) < 0) {
330 log_warn("%s: error setting IP_TTL", __func__
);
338 sock_set_ipv4_mcast_ttl(int fd
, uint8_t ttl
)
340 if (setsockopt(fd
, IPPROTO_IP
, IP_MULTICAST_TTL
, (char *)&ttl
, sizeof(ttl
)) < 0) {
341 log_warn("%s: error setting IP_MULTICAST_TTL to %d", __func__
, ttl
);
349 #if defined(HAVE_IP_PKTINFO)
351 sock_set_ipv4_pktinfo(int fd
, int enable
)
353 if (setsockopt(fd
, IPPROTO_IP
, IP_PKTINFO
, &enable
, sizeof(enable
)) < 0) {
354 log_warn("%s: error setting IP_PKTINFO", __func__
);
360 #elif defined(HAVE_IP_RECVDSTADDR)
362 sock_set_ipv4_recvdstaddr(int fd
, int enable
)
364 if (setsockopt(fd
, IPPROTO_IP
, IP_RECVDSTADDR
, &enable
, sizeof(enable
)) < 0) {
365 log_warn("%s: error setting IP_RECVDSTADDR", __func__
);
372 #error "Unsupported socket API"
374 #endif /* MSG_MCAST */
377 sock_set_ipv4_mcast(struct iface
*iface
)
379 struct in_addr if_addr
;
381 if_addr
.s_addr
= if_get_ipv4_addr(iface
);
383 if (setsockopt_ipv4_multicast_if(global
.ipv4
.ldp_disc_socket
,
384 if_addr
, iface
->ifindex
) < 0) {
385 log_warn("%s: error setting IP_MULTICAST_IF, interface %s",
386 __func__
, iface
->name
);
394 sock_set_ipv4_mcast_loop(int fd
)
396 return (setsockopt_ipv4_multicast_loop(fd
, 0));
400 sock_set_ipv6_dscp(int fd
, int dscp
)
402 if (setsockopt(fd
, IPPROTO_IPV6
, IPV6_TCLASS
, &dscp
, sizeof(dscp
)) < 0) {
403 log_warn("%s: error setting IPV6_TCLASS", __func__
);
411 sock_set_ipv6_pktinfo(int fd
, int enable
)
413 if (setsockopt(fd
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
, &enable
, sizeof(enable
)) < 0) {
414 log_warn("%s: error setting IPV6_RECVPKTINFO", __func__
);
422 sock_set_ipv6_minhopcount(int fd
, int hoplimit
)
424 return (sockopt_minttl(AF_INET6
, fd
, hoplimit
));
428 sock_set_ipv6_ucast_hops(int fd
, int hoplimit
)
430 if (setsockopt(fd
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
,
431 &hoplimit
, sizeof(hoplimit
)) < 0) {
432 log_warn("%s: error setting IPV6_UNICAST_HOPS", __func__
);
440 sock_set_ipv6_mcast_hops(int fd
, int hoplimit
)
442 if (setsockopt(fd
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
,
443 &hoplimit
, sizeof(hoplimit
)) < 0) {
444 log_warn("%s: error setting IPV6_MULTICAST_HOPS", __func__
);
452 sock_set_ipv6_mcast(struct iface
*iface
)
454 if (setsockopt(global
.ipv6
.ldp_disc_socket
, IPPROTO_IPV6
,
455 IPV6_MULTICAST_IF
, &iface
->ifindex
, sizeof(iface
->ifindex
)) < 0) {
456 log_warn("%s: error setting IPV6_MULTICAST_IF, interface %s",
457 __func__
, iface
->name
);
465 sock_set_ipv6_mcast_loop(int fd
)
467 unsigned int loop
= 0;
469 if (setsockopt(fd
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
,
470 &loop
, sizeof(loop
)) < 0) {
471 log_warn("%s: error setting IPV6_MULTICAST_LOOP", __func__
);