4 * Copyright (c) 2016 Renato Westphal <renato@openbsd.org>
5 * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
6 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
7 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
32 extern struct zebra_privs_t ldpd_privs
;
33 extern struct zebra_privs_t ldpe_privs
;
36 ldp_create_socket(int af
, enum socket_type type
)
38 int fd
, domain
, proto
;
40 struct sockaddr_storage local_sa
;
49 case LDP_SOCKET_EDISC
:
53 case LDP_SOCKET_SESSION
:
58 fatalx("ldp_create_socket: unknown socket type");
60 fd
= socket(af
, domain
, proto
);
62 log_warn("%s: error creating socket", __func__
);
65 sock_set_nonblock(fd
);
66 sockopt_v6only(af
, fd
);
68 /* bind to a local address/port */
71 /* listen on all addresses */
72 memset(&addr
, 0, sizeof(addr
));
73 memcpy(&local_sa
, addr2sa(af
, &addr
, LDP_PORT
),
76 case LDP_SOCKET_EDISC
:
77 case LDP_SOCKET_SESSION
:
78 addr
= (ldp_af_conf_get(ldpd_conf
, af
))->trans_addr
;
79 memcpy(&local_sa
, addr2sa(af
, &addr
, LDP_PORT
),
81 /* ignore any possible error */
82 sock_set_bindany(fd
, 1);
85 if (ldpd_privs
.change(ZPRIVS_RAISE
))
86 log_warn("%s: could not raise privs", __func__
);
87 if (sock_set_reuse(fd
, 1) == -1) {
88 if (ldpd_privs
.change(ZPRIVS_LOWER
))
89 log_warn("%s: could not lower privs", __func__
);
93 if (bind(fd
, (struct sockaddr
*)&local_sa
,
94 sockaddr_len((struct sockaddr
*)&local_sa
)) == -1) {
96 if (ldpd_privs
.change(ZPRIVS_LOWER
))
97 log_warn("%s: could not lower privs", __func__
);
98 log_warnx("%s: error binding socket: %s", __func__
,
99 safe_strerror(save_errno
));
103 if (ldpd_privs
.change(ZPRIVS_LOWER
))
104 log_warn("%s: could not lower privs", __func__
);
109 if (sock_set_ipv4_tos(fd
, IPTOS_PREC_INTERNETCONTROL
) == -1) {
113 if (type
== LDP_SOCKET_DISC
) {
114 if (sock_set_ipv4_mcast_ttl(fd
,
115 IP_DEFAULT_MULTICAST_TTL
) == -1) {
119 if (sock_set_ipv4_mcast_loop(fd
) == -1) {
124 if (type
== LDP_SOCKET_DISC
|| type
== LDP_SOCKET_EDISC
) {
125 if (sock_set_ipv4_recvif(fd
, 1) == -1) {
130 #if defined(HAVE_IP_PKTINFO)
131 if (sock_set_ipv4_pktinfo(fd
, 1) == -1) {
135 #elif defined(HAVE_IP_RECVDSTADDR)
136 if (sock_set_ipv4_recvdstaddr(fd
, 1) == -1) {
141 #error "Unsupported socket API"
143 #endif /* MSG_MCAST */
145 if (type
== LDP_SOCKET_SESSION
) {
146 if (sock_set_ipv4_ucast_ttl(fd
, 255) == -1) {
153 if (sock_set_ipv6_dscp(fd
, IPTOS_PREC_INTERNETCONTROL
) == -1) {
157 if (type
== LDP_SOCKET_DISC
) {
158 if (sock_set_ipv6_mcast_loop(fd
) == -1) {
162 if (sock_set_ipv6_mcast_hops(fd
, 255) == -1) {
166 if (!(ldpd_conf
->ipv6
.flags
& F_LDPD_AF_NO_GTSM
)) {
167 /* ignore any possible error */
168 sock_set_ipv6_minhopcount(fd
, 255);
171 if (type
== LDP_SOCKET_DISC
|| type
== LDP_SOCKET_EDISC
) {
172 if (sock_set_ipv6_pktinfo(fd
, 1) == -1) {
177 if (type
== LDP_SOCKET_SESSION
) {
178 if (sock_set_ipv6_ucast_hops(fd
, 255) == -1) {
186 case LDP_SOCKET_DISC
:
187 case LDP_SOCKET_EDISC
:
188 sock_set_recvbuf(fd
);
190 case LDP_SOCKET_SESSION
:
191 if (listen(fd
, LDP_BACKLOG
) == -1)
192 log_warn("%s: error listening on socket", __func__
);
196 if (setsockopt(fd
, IPPROTO_TCP
, TCP_MD5SIG
, &opt
,
197 sizeof(opt
)) == -1) {
198 if (errno
== ENOPROTOOPT
) { /* system w/o md5sig */
199 log_warnx("md5sig not available, disabling");
200 sysdep
.no_md5sig
= 1;
214 sock_set_nonblock(int fd
)
218 if ((flags
= fcntl(fd
, F_GETFL
, 0)) == -1)
219 fatal("fcntl F_GETFL");
223 if ((flags
= fcntl(fd
, F_SETFL
, flags
)) == -1)
224 fatal("fcntl F_SETFL");
228 sock_set_cloexec(int fd
)
232 if ((flags
= fcntl(fd
, F_GETFD
, 0)) == -1)
233 fatal("fcntl F_GETFD");
237 if ((flags
= fcntl(fd
, F_SETFD
, flags
)) == -1)
238 fatal("fcntl F_SETFD");
242 sock_set_recvbuf(int fd
)
247 while (setsockopt(fd
, SOL_SOCKET
, SO_RCVBUF
, &bsize
,
248 sizeof(bsize
)) == -1)
253 sock_set_reuse(int fd
, int enable
)
255 if (setsockopt(fd
, SOL_SOCKET
, SO_REUSEADDR
, &enable
,
257 log_warn("%s: error setting SO_REUSEADDR", __func__
);
265 sock_set_bindany(int fd
, int enable
)
267 #ifdef HAVE_SO_BINDANY
268 if (ldpd_privs
.change(ZPRIVS_RAISE
))
269 log_warn("%s: could not raise privs", __func__
);
270 if (setsockopt(fd
, SOL_SOCKET
, SO_BINDANY
, &enable
,
272 if (ldpd_privs
.change(ZPRIVS_LOWER
))
273 log_warn("%s: could not lower privs", __func__
);
274 log_warn("%s: error setting SO_BINDANY", __func__
);
277 if (ldpd_privs
.change(ZPRIVS_LOWER
))
278 log_warn("%s: could not lower privs", __func__
);
280 #elif defined(HAVE_IP_FREEBIND)
281 if (setsockopt(fd
, IPPROTO_IP
, IP_FREEBIND
, &enable
, sizeof(int)) < 0) {
282 log_warn("%s: error setting IP_FREEBIND", __func__
);
287 log_warnx("%s: missing SO_BINDANY and IP_FREEBIND, unable to bind "
288 "to a nonlocal IP address", __func__
);
290 #endif /* HAVE_SO_BINDANY */
295 * Set MD5 key for the socket, for the given peer address. If the password
296 * is NULL or zero-length, the option will be disabled.
299 sock_set_md5sig(int fd
, int af
, union ldpd_addr
*addr
, const char *password
)
302 int save_errno
= ENOSYS
;
303 #if HAVE_DECL_TCP_MD5SIG
309 #if HAVE_DECL_TCP_MD5SIG
310 memcpy(&su
, addr2sa(af
, addr
, 0), sizeof(su
));
312 if (ldpe_privs
.change(ZPRIVS_RAISE
)) {
313 log_warn("%s: could not raise privs", __func__
);
316 ret
= sockopt_tcp_signature(fd
, &su
, password
);
318 if (ldpe_privs
.change(ZPRIVS_LOWER
))
319 log_warn("%s: could not lower privs", __func__
);
320 #endif /* HAVE_TCP_MD5SIG */
322 log_warnx("%s: can't set TCP_MD5SIG option on fd %d: %s",
323 __func__
, fd
, safe_strerror(save_errno
));
330 sock_set_ipv4_tos(int fd
, int tos
)
332 if (setsockopt(fd
, IPPROTO_IP
, IP_TOS
, (int *)&tos
, sizeof(tos
)) < 0) {
333 log_warn("%s: error setting IP_TOS to 0x%x", __func__
, tos
);
341 sock_set_ipv4_recvif(int fd
, int enable
)
343 return (setsockopt_ifindex(AF_INET
, fd
, enable
));
347 sock_set_ipv4_minttl(int fd
, int ttl
)
349 return (sockopt_minttl(AF_INET
, fd
, ttl
));
353 sock_set_ipv4_ucast_ttl(int fd
, int ttl
)
355 if (setsockopt(fd
, IPPROTO_IP
, IP_TTL
, &ttl
, sizeof(ttl
)) < 0) {
356 log_warn("%s: error setting IP_TTL", __func__
);
364 sock_set_ipv4_mcast_ttl(int fd
, uint8_t ttl
)
366 if (setsockopt(fd
, IPPROTO_IP
, IP_MULTICAST_TTL
,
367 (char *)&ttl
, sizeof(ttl
)) < 0) {
368 log_warn("%s: error setting IP_MULTICAST_TTL to %d",
377 #if defined(HAVE_IP_PKTINFO)
379 sock_set_ipv4_pktinfo(int fd
, int enable
)
381 if (setsockopt(fd
, IPPROTO_IP
, IP_PKTINFO
, &enable
,
382 sizeof(enable
)) < 0) {
383 log_warn("%s: error setting IP_PKTINFO", __func__
);
389 #elif defined(HAVE_IP_RECVDSTADDR)
391 sock_set_ipv4_recvdstaddr(int fd
, int enable
)
393 if (setsockopt(fd
, IPPROTO_IP
, IP_RECVDSTADDR
, &enable
,
394 sizeof(enable
)) < 0) {
395 log_warn("%s: error setting IP_RECVDSTADDR", __func__
);
402 #error "Unsupported socket API"
404 #endif /* MSG_MCAST */
407 sock_set_ipv4_mcast(struct iface
*iface
)
409 struct in_addr if_addr
;
411 if_addr
.s_addr
= if_get_ipv4_addr(iface
);
413 if (setsockopt_ipv4_multicast_if(global
.ipv4
.ldp_disc_socket
,
414 if_addr
, iface
->ifindex
) < 0) {
415 log_warn("%s: error setting IP_MULTICAST_IF, interface %s",
416 __func__
, iface
->name
);
424 sock_set_ipv4_mcast_loop(int fd
)
426 return (setsockopt_ipv4_multicast_loop(fd
, 0));
430 sock_set_ipv6_dscp(int fd
, int dscp
)
432 if (setsockopt(fd
, IPPROTO_IPV6
, IPV6_TCLASS
, &dscp
,
434 log_warn("%s: error setting IPV6_TCLASS", __func__
);
442 sock_set_ipv6_pktinfo(int fd
, int enable
)
444 if (setsockopt(fd
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
, &enable
,
445 sizeof(enable
)) < 0) {
446 log_warn("%s: error setting IPV6_RECVPKTINFO", __func__
);
454 sock_set_ipv6_minhopcount(int fd
, int hoplimit
)
456 return (sockopt_minttl(AF_INET6
, fd
, hoplimit
));
460 sock_set_ipv6_ucast_hops(int fd
, int hoplimit
)
462 if (setsockopt(fd
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
,
463 &hoplimit
, sizeof(hoplimit
)) < 0) {
464 log_warn("%s: error setting IPV6_UNICAST_HOPS", __func__
);
472 sock_set_ipv6_mcast_hops(int fd
, int hoplimit
)
474 if (setsockopt(fd
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
,
475 &hoplimit
, sizeof(hoplimit
)) < 0) {
476 log_warn("%s: error setting IPV6_MULTICAST_HOPS", __func__
);
484 sock_set_ipv6_mcast(struct iface
*iface
)
486 if (setsockopt(global
.ipv6
.ldp_disc_socket
, IPPROTO_IPV6
,
487 IPV6_MULTICAST_IF
, &iface
->ifindex
, sizeof(iface
->ifindex
)) < 0) {
488 log_warn("%s: error setting IPV6_MULTICAST_IF, interface %s",
489 __func__
, iface
->name
);
497 sock_set_ipv6_mcast_loop(int fd
)
499 unsigned int loop
= 0;
501 if (setsockopt(fd
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
,
502 &loop
, sizeof(loop
)) < 0) {
503 log_warn("%s: error setting IPV6_MULTICAST_LOOP", __func__
);