xref: /openbsd-src/usr.sbin/ldpd/socket.c (revision df69c215c7c66baf660f3f65414fd34796c96152)
1*df69c215Sderaadt /*	$OpenBSD: socket.c,v 1.10 2019/06/28 13:32:48 deraadt Exp $ */
2029cacd7Srenato 
3029cacd7Srenato /*
4029cacd7Srenato  * Copyright (c) 2016 Renato Westphal <renato@openbsd.org>
5029cacd7Srenato  * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
6029cacd7Srenato  * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
7029cacd7Srenato  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
8029cacd7Srenato  *
9029cacd7Srenato  * Permission to use, copy, modify, and distribute this software for any
10029cacd7Srenato  * purpose with or without fee is hereby granted, provided that the above
11029cacd7Srenato  * copyright notice and this permission notice appear in all copies.
12029cacd7Srenato  *
13029cacd7Srenato  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14029cacd7Srenato  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15029cacd7Srenato  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16029cacd7Srenato  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17029cacd7Srenato  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18029cacd7Srenato  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19029cacd7Srenato  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20029cacd7Srenato  */
21029cacd7Srenato 
22029cacd7Srenato #include <sys/types.h>
23029cacd7Srenato #include <netinet/in.h>
24029cacd7Srenato #include <netinet/ip.h>
25029cacd7Srenato #include <netinet/tcp.h>
26029cacd7Srenato #include <string.h>
27029cacd7Srenato #include <unistd.h>
28029cacd7Srenato #include <errno.h>
29029cacd7Srenato 
30029cacd7Srenato #include "ldpd.h"
31029cacd7Srenato #include "ldpe.h"
32029cacd7Srenato #include "log.h"
33029cacd7Srenato 
3462a29563Srenato int
ldp_create_socket(int af,enum socket_type type)35a8c39dc0Srenato ldp_create_socket(int af, enum socket_type type)
3662a29563Srenato {
3762a29563Srenato 	int			 fd, domain, proto;
38a8c39dc0Srenato 	union ldpd_addr		 addr;
39a8c39dc0Srenato 	struct sockaddr_storage	 local_sa;
4062a29563Srenato 	int			 opt;
4162a29563Srenato 
4262a29563Srenato 	/* create socket */
4362a29563Srenato 	switch (type) {
4462a29563Srenato 	case LDP_SOCKET_DISC:
4562a29563Srenato 	case LDP_SOCKET_EDISC:
4662a29563Srenato 		domain = SOCK_DGRAM;
4762a29563Srenato 		proto = IPPROTO_UDP;
4862a29563Srenato 		break;
4962a29563Srenato 	case LDP_SOCKET_SESSION:
5062a29563Srenato 		domain = SOCK_STREAM;
5162a29563Srenato 		proto = IPPROTO_TCP;
5262a29563Srenato 		break;
5362a29563Srenato 	default:
5462a29563Srenato 		fatalx("ldp_create_socket: unknown socket type");
5562a29563Srenato 	}
56a8c39dc0Srenato 	fd = socket(af, domain | SOCK_NONBLOCK | SOCK_CLOEXEC, proto);
5762a29563Srenato 	if (fd == -1) {
5862a29563Srenato 		log_warn("%s: error creating socket", __func__);
5962a29563Srenato 		return (-1);
6062a29563Srenato 	}
6162a29563Srenato 
6262a29563Srenato 	/* bind to a local address/port */
6362a29563Srenato 	switch (type) {
6462a29563Srenato 	case LDP_SOCKET_DISC:
6562a29563Srenato 		/* listen on all addresses */
66a8c39dc0Srenato 		memset(&addr, 0, sizeof(addr));
67a8c39dc0Srenato 		memcpy(&local_sa, addr2sa(af, &addr, LDP_PORT),
68a8c39dc0Srenato 		    sizeof(local_sa));
6962a29563Srenato 		break;
7062a29563Srenato 	case LDP_SOCKET_EDISC:
7162a29563Srenato 	case LDP_SOCKET_SESSION:
72a8c39dc0Srenato 		addr = (ldp_af_conf_get(ldpd_conf, af))->trans_addr;
73a8c39dc0Srenato 		memcpy(&local_sa, addr2sa(af, &addr, LDP_PORT),
74a8c39dc0Srenato 		    sizeof(local_sa));
753ef9ea36Srenato 		if (sock_set_bindany(fd, 1) == -1) {
763ef9ea36Srenato 			close(fd);
773ef9ea36Srenato 			return (-1);
783ef9ea36Srenato 		}
7962a29563Srenato 		break;
8062a29563Srenato 	}
8162a29563Srenato 	if (sock_set_reuse(fd, 1) == -1) {
8262a29563Srenato 		close(fd);
8362a29563Srenato 		return (-1);
8462a29563Srenato 	}
85a8c39dc0Srenato 	if (bind(fd, (struct sockaddr *)&local_sa, local_sa.ss_len) == -1) {
8662a29563Srenato 		log_warn("%s: error binding socket", __func__);
8762a29563Srenato 		close(fd);
8862a29563Srenato 		return (-1);
8962a29563Srenato 	}
9062a29563Srenato 
9162a29563Srenato 	/* set options */
92a8c39dc0Srenato 	switch (af) {
93a8c39dc0Srenato 	case AF_INET:
9462a29563Srenato 		if (sock_set_ipv4_tos(fd, IPTOS_PREC_INTERNETCONTROL) == -1) {
9562a29563Srenato 			close(fd);
9662a29563Srenato 			return (-1);
9762a29563Srenato 		}
9862a29563Srenato 		if (type == LDP_SOCKET_DISC) {
9962a29563Srenato 			if (sock_set_ipv4_mcast_ttl(fd,
10062a29563Srenato 			    IP_DEFAULT_MULTICAST_TTL) == -1) {
10162a29563Srenato 				close(fd);
10262a29563Srenato 				return (-1);
10362a29563Srenato 			}
10462a29563Srenato 			if (sock_set_ipv4_mcast_loop(fd) == -1) {
10562a29563Srenato 				close(fd);
10662a29563Srenato 				return (-1);
10762a29563Srenato 			}
10862a29563Srenato 		}
10962a29563Srenato 		if (type == LDP_SOCKET_DISC || type == LDP_SOCKET_EDISC) {
11062a29563Srenato 			if (sock_set_ipv4_recvif(fd, 1) == -1) {
11162a29563Srenato 				close(fd);
11262a29563Srenato 				return (-1);
11362a29563Srenato 			}
11462a29563Srenato 		}
1155ff72af8Srenato 		if (type == LDP_SOCKET_SESSION) {
1165ff72af8Srenato 			if (sock_set_ipv4_ucast_ttl(fd, 255) == -1) {
1175ff72af8Srenato 				close(fd);
1185ff72af8Srenato 				return (-1);
1195ff72af8Srenato 			}
1205ff72af8Srenato 		}
121a8c39dc0Srenato 		break;
122a8c39dc0Srenato 	case AF_INET6:
123a8c39dc0Srenato 		if (sock_set_ipv6_dscp(fd, IPTOS_PREC_INTERNETCONTROL) == -1) {
124a8c39dc0Srenato 			close(fd);
125a8c39dc0Srenato 			return (-1);
126a8c39dc0Srenato 		}
127a8c39dc0Srenato 		if (type == LDP_SOCKET_DISC) {
128a8c39dc0Srenato 			if (sock_set_ipv6_mcast_loop(fd) == -1) {
129a8c39dc0Srenato 				close(fd);
130a8c39dc0Srenato 				return (-1);
131a8c39dc0Srenato 			}
1325ff72af8Srenato 			if (sock_set_ipv6_mcast_hops(fd, 255) == -1) {
1335ff72af8Srenato 				close(fd);
1345ff72af8Srenato 				return (-1);
1355ff72af8Srenato 			}
1365ff72af8Srenato 			if (!(ldpd_conf->ipv6.flags & F_LDPD_AF_NO_GTSM)) {
1375ff72af8Srenato 				if (sock_set_ipv6_minhopcount(fd, 255) == -1) {
1385ff72af8Srenato 					close(fd);
1395ff72af8Srenato 					return (-1);
1405ff72af8Srenato 				}
1415ff72af8Srenato 			}
142a8c39dc0Srenato 		}
143a8c39dc0Srenato 		if (type == LDP_SOCKET_DISC || type == LDP_SOCKET_EDISC) {
144a8c39dc0Srenato 			if (sock_set_ipv6_pktinfo(fd, 1) == -1) {
145a8c39dc0Srenato 				close(fd);
146a8c39dc0Srenato 				return (-1);
147a8c39dc0Srenato 			}
148a8c39dc0Srenato 		}
1495ff72af8Srenato 		if (type == LDP_SOCKET_SESSION) {
1505ff72af8Srenato 			if (sock_set_ipv6_ucast_hops(fd, 255) == -1) {
1515ff72af8Srenato 				close(fd);
1525ff72af8Srenato 				return (-1);
1535ff72af8Srenato 			}
1545ff72af8Srenato 		}
155a8c39dc0Srenato 		break;
156a8c39dc0Srenato 	}
15762a29563Srenato 	switch (type) {
15862a29563Srenato 	case LDP_SOCKET_DISC:
15962a29563Srenato 	case LDP_SOCKET_EDISC:
16062a29563Srenato 		sock_set_recvbuf(fd);
16162a29563Srenato 		break;
16262a29563Srenato 	case LDP_SOCKET_SESSION:
16362a29563Srenato 		if (listen(fd, LDP_BACKLOG) == -1)
16462a29563Srenato 			log_warn("%s: error listening on socket", __func__);
16562a29563Srenato 
16662a29563Srenato 		opt = 1;
16762a29563Srenato 		if (setsockopt(fd, IPPROTO_TCP, TCP_MD5SIG, &opt,
16862a29563Srenato 		    sizeof(opt)) == -1) {
16962a29563Srenato 			if (errno == ENOPROTOOPT) {	/* system w/o md5sig */
17062a29563Srenato 				log_warnx("md5sig not available, disabling");
17162a29563Srenato 				sysdep.no_md5sig = 1;
17262a29563Srenato 			} else {
17362a29563Srenato 				close(fd);
17462a29563Srenato 				return (-1);
17562a29563Srenato 			}
17662a29563Srenato 		}
17762a29563Srenato 		break;
17862a29563Srenato 	}
17962a29563Srenato 
18062a29563Srenato 	return (fd);
18162a29563Srenato }
18262a29563Srenato 
183029cacd7Srenato void
sock_set_recvbuf(int fd)184029cacd7Srenato sock_set_recvbuf(int fd)
185029cacd7Srenato {
186029cacd7Srenato 	int	bsize;
187029cacd7Srenato 
188029cacd7Srenato 	bsize = 65535;
189029cacd7Srenato 	while (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bsize,
190029cacd7Srenato 	    sizeof(bsize)) == -1)
191029cacd7Srenato 		bsize /= 2;
192029cacd7Srenato }
193029cacd7Srenato 
194029cacd7Srenato int
sock_set_reuse(int fd,int enable)195029cacd7Srenato sock_set_reuse(int fd, int enable)
196029cacd7Srenato {
197029cacd7Srenato 	if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &enable,
198*df69c215Sderaadt 	    sizeof(int)) == -1) {
199029cacd7Srenato 		log_warn("%s: error setting SO_REUSEADDR", __func__);
200029cacd7Srenato 		return (-1);
201029cacd7Srenato 	}
202029cacd7Srenato 
203029cacd7Srenato 	return (0);
204029cacd7Srenato }
205029cacd7Srenato 
206029cacd7Srenato int
sock_set_bindany(int fd,int enable)2073ef9ea36Srenato sock_set_bindany(int fd, int enable)
2083ef9ea36Srenato {
2093ef9ea36Srenato 	if (setsockopt(fd, SOL_SOCKET, SO_BINDANY, &enable,
210*df69c215Sderaadt 	    sizeof(int)) == -1) {
2113ef9ea36Srenato 		log_warn("%s: error setting SO_BINDANY", __func__);
2123ef9ea36Srenato 		return (-1);
2133ef9ea36Srenato 	}
2143ef9ea36Srenato 
2153ef9ea36Srenato 	return (0);
2163ef9ea36Srenato }
2173ef9ea36Srenato 
2183ef9ea36Srenato int
sock_set_ipv4_tos(int fd,int tos)219029cacd7Srenato sock_set_ipv4_tos(int fd, int tos)
220029cacd7Srenato {
221*df69c215Sderaadt 	if (setsockopt(fd, IPPROTO_IP, IP_TOS, (int *)&tos, sizeof(tos)) == -1) {
222029cacd7Srenato 		log_warn("%s: error setting IP_TOS to 0x%x", __func__, tos);
223029cacd7Srenato 		return (-1);
224029cacd7Srenato 	}
225029cacd7Srenato 
226029cacd7Srenato 	return (0);
227029cacd7Srenato }
228029cacd7Srenato 
229029cacd7Srenato int
sock_set_ipv4_recvif(int fd,int enable)230029cacd7Srenato sock_set_ipv4_recvif(int fd, int enable)
231029cacd7Srenato {
232029cacd7Srenato 	if (setsockopt(fd, IPPROTO_IP, IP_RECVIF, &enable,
233*df69c215Sderaadt 	    sizeof(enable)) == -1) {
234029cacd7Srenato 		log_warn("%s: error setting IP_RECVIF", __func__);
235029cacd7Srenato 		return (-1);
236029cacd7Srenato 	}
237029cacd7Srenato 	return (0);
238029cacd7Srenato }
239029cacd7Srenato 
240029cacd7Srenato int
sock_set_ipv4_minttl(int fd,int ttl)2415ff72af8Srenato sock_set_ipv4_minttl(int fd, int ttl)
2425ff72af8Srenato {
243*df69c215Sderaadt 	if (setsockopt(fd, IPPROTO_IP, IP_MINTTL, &ttl, sizeof(ttl)) == -1) {
2445ff72af8Srenato 		log_warn("%s: error setting IP_MINTTL", __func__);
2455ff72af8Srenato 		return (-1);
2465ff72af8Srenato 	}
2475ff72af8Srenato 
2485ff72af8Srenato 	return (0);
2495ff72af8Srenato }
2505ff72af8Srenato 
2515ff72af8Srenato int
sock_set_ipv4_ucast_ttl(int fd,int ttl)2525ff72af8Srenato sock_set_ipv4_ucast_ttl(int fd, int ttl)
2535ff72af8Srenato {
254*df69c215Sderaadt 	if (setsockopt(fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)) == -1) {
2555ff72af8Srenato 		log_warn("%s: error setting IP_TTL", __func__);
2565ff72af8Srenato 		return (-1);
2575ff72af8Srenato 	}
2585ff72af8Srenato 
2595ff72af8Srenato 	return (0);
2605ff72af8Srenato }
2615ff72af8Srenato 
2625ff72af8Srenato int
sock_set_ipv4_mcast_ttl(int fd,uint8_t ttl)2635ff72af8Srenato sock_set_ipv4_mcast_ttl(int fd, uint8_t ttl)
2645ff72af8Srenato {
2655ff72af8Srenato 	if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL,
266*df69c215Sderaadt 	    (char *)&ttl, sizeof(ttl)) == -1) {
2675ff72af8Srenato 		log_warn("%s: error setting IP_MULTICAST_TTL to %d",
2685ff72af8Srenato 		    __func__, ttl);
2695ff72af8Srenato 		return (-1);
2705ff72af8Srenato 	}
2715ff72af8Srenato 
2725ff72af8Srenato 	return (0);
2735ff72af8Srenato }
2745ff72af8Srenato 
2755ff72af8Srenato int
sock_set_ipv4_mcast(struct iface * iface)276029cacd7Srenato sock_set_ipv4_mcast(struct iface *iface)
277029cacd7Srenato {
278a8c39dc0Srenato 	in_addr_t		 addr;
279029cacd7Srenato 
280a8c39dc0Srenato 	addr = if_get_ipv4_addr(iface);
281029cacd7Srenato 
282a8c39dc0Srenato 	if (setsockopt(global.ipv4.ldp_disc_socket, IPPROTO_IP, IP_MULTICAST_IF,
283*df69c215Sderaadt 	    &addr, sizeof(addr)) == -1) {
284029cacd7Srenato 		log_warn("%s: error setting IP_MULTICAST_IF, interface %s",
285029cacd7Srenato 		    __func__, iface->name);
286029cacd7Srenato 		return (-1);
287029cacd7Srenato 	}
288029cacd7Srenato 
289029cacd7Srenato 	return (0);
290029cacd7Srenato }
291029cacd7Srenato 
292029cacd7Srenato int
sock_set_ipv4_mcast_loop(int fd)293029cacd7Srenato sock_set_ipv4_mcast_loop(int fd)
294029cacd7Srenato {
295029cacd7Srenato 	uint8_t	loop = 0;
296029cacd7Srenato 
297029cacd7Srenato 	if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP,
298*df69c215Sderaadt 	    (char *)&loop, sizeof(loop)) == -1) {
299029cacd7Srenato 		log_warn("%s: error setting IP_MULTICAST_LOOP", __func__);
300029cacd7Srenato 		return (-1);
301029cacd7Srenato 	}
302029cacd7Srenato 
303029cacd7Srenato 	return (0);
304029cacd7Srenato }
305a8c39dc0Srenato 
306a8c39dc0Srenato int
sock_set_ipv6_dscp(int fd,int dscp)307a8c39dc0Srenato sock_set_ipv6_dscp(int fd, int dscp)
308a8c39dc0Srenato {
309a8c39dc0Srenato 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &dscp,
310*df69c215Sderaadt 	    sizeof(dscp)) == -1) {
311a8c39dc0Srenato 		log_warn("%s: error setting IPV6_TCLASS", __func__);
312a8c39dc0Srenato 		return (-1);
313a8c39dc0Srenato 	}
314a8c39dc0Srenato 
315a8c39dc0Srenato 	return (0);
316a8c39dc0Srenato }
317a8c39dc0Srenato 
318a8c39dc0Srenato int
sock_set_ipv6_pktinfo(int fd,int enable)319a8c39dc0Srenato sock_set_ipv6_pktinfo(int fd, int enable)
320a8c39dc0Srenato {
321a8c39dc0Srenato 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &enable,
322*df69c215Sderaadt 	    sizeof(enable)) == -1) {
323a8c39dc0Srenato 		log_warn("%s: error setting IPV6_RECVPKTINFO", __func__);
324a8c39dc0Srenato 		return (-1);
325a8c39dc0Srenato 	}
326a8c39dc0Srenato 
327a8c39dc0Srenato 	return (0);
328a8c39dc0Srenato }
329a8c39dc0Srenato 
330a8c39dc0Srenato int
sock_set_ipv6_minhopcount(int fd,int hoplimit)3315ff72af8Srenato sock_set_ipv6_minhopcount(int fd, int hoplimit)
3325ff72af8Srenato {
3335ff72af8Srenato 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_MINHOPCOUNT,
334*df69c215Sderaadt 	    &hoplimit, sizeof(hoplimit)) == -1) {
3355ff72af8Srenato 		log_warn("%s: error setting IPV6_MINHOPCOUNT", __func__);
3365ff72af8Srenato 		return (-1);
3375ff72af8Srenato 	}
3385ff72af8Srenato 
3395ff72af8Srenato 	return (0);
3405ff72af8Srenato }
3415ff72af8Srenato 
3425ff72af8Srenato int
sock_set_ipv6_ucast_hops(int fd,int hoplimit)3435ff72af8Srenato sock_set_ipv6_ucast_hops(int fd, int hoplimit)
3445ff72af8Srenato {
3455ff72af8Srenato 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
346*df69c215Sderaadt 	    &hoplimit, sizeof(hoplimit)) == -1) {
3475ff72af8Srenato 		log_warn("%s: error setting IPV6_UNICAST_HOPS", __func__);
3485ff72af8Srenato 		return (-1);
3495ff72af8Srenato 	}
3505ff72af8Srenato 
3515ff72af8Srenato 	return (0);
3525ff72af8Srenato }
3535ff72af8Srenato 
3545ff72af8Srenato int
sock_set_ipv6_mcast_hops(int fd,int hoplimit)3555ff72af8Srenato sock_set_ipv6_mcast_hops(int fd, int hoplimit)
3565ff72af8Srenato {
3575ff72af8Srenato 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
358*df69c215Sderaadt 	    &hoplimit, sizeof(hoplimit)) == -1) {
3595ff72af8Srenato 		log_warn("%s: error setting IPV6_MULTICAST_HOPS", __func__);
3605ff72af8Srenato 		return (-1);
3615ff72af8Srenato 	}
3625ff72af8Srenato 
3635ff72af8Srenato 	return (0);
3645ff72af8Srenato }
3655ff72af8Srenato 
3665ff72af8Srenato int
sock_set_ipv6_mcast(struct iface * iface)367a8c39dc0Srenato sock_set_ipv6_mcast(struct iface *iface)
368a8c39dc0Srenato {
369a8c39dc0Srenato 	if (setsockopt(global.ipv6.ldp_disc_socket, IPPROTO_IPV6,
370*df69c215Sderaadt 	    IPV6_MULTICAST_IF, &iface->ifindex, sizeof(iface->ifindex)) == -1) {
371a8c39dc0Srenato 		log_warn("%s: error setting IPV6_MULTICAST_IF, interface %s",
372a8c39dc0Srenato 		    __func__, iface->name);
373a8c39dc0Srenato 		return (-1);
374a8c39dc0Srenato 	}
375a8c39dc0Srenato 
376a8c39dc0Srenato 	return (0);
377a8c39dc0Srenato }
378a8c39dc0Srenato 
379a8c39dc0Srenato int
sock_set_ipv6_mcast_loop(int fd)380a8c39dc0Srenato sock_set_ipv6_mcast_loop(int fd)
381a8c39dc0Srenato {
382a8c39dc0Srenato 	unsigned int	loop = 0;
383a8c39dc0Srenato 
384a8c39dc0Srenato 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
385*df69c215Sderaadt 	    &loop, sizeof(loop)) == -1) {
386a8c39dc0Srenato 		log_warn("%s: error setting IPV6_MULTICAST_LOOP", __func__);
387a8c39dc0Srenato 		return (-1);
388a8c39dc0Srenato 	}
389a8c39dc0Srenato 
390a8c39dc0Srenato 	return (0);
391a8c39dc0Srenato }
392