1/*	$OpenBSD: socket.c,v 1.10 2019/06/28 13:32:48 deraadt Exp $ */
2
3/*
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>
8 *
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.
12 *
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.
20 */
21
22#include <sys/types.h>
23#include <netinet/in.h>
24#include <netinet/ip.h>
25#include <netinet/tcp.h>
26#include <string.h>
27#include <unistd.h>
28#include <errno.h>
29
30#include "ldpd.h"
31#include "ldpe.h"
32#include "log.h"
33
34int
35ldp_create_socket(int af, enum socket_type type)
36{
37	int			 fd, domain, proto;
38	union ldpd_addr		 addr;
39	struct sockaddr_storage	 local_sa;
40	int			 opt;
41
42	/* create socket */
43	switch (type) {
44	case LDP_SOCKET_DISC:
45	case LDP_SOCKET_EDISC:
46		domain = SOCK_DGRAM;
47		proto = IPPROTO_UDP;
48		break;
49	case LDP_SOCKET_SESSION:
50		domain = SOCK_STREAM;
51		proto = IPPROTO_TCP;
52		break;
53	default:
54		fatalx("ldp_create_socket: unknown socket type");
55	}
56	fd = socket(af, domain | SOCK_NONBLOCK | SOCK_CLOEXEC, proto);
57	if (fd == -1) {
58		log_warn("%s: error creating socket", __func__);
59		return (-1);
60	}
61
62	/* bind to a local address/port */
63	switch (type) {
64	case LDP_SOCKET_DISC:
65		/* listen on all addresses */
66		memset(&addr, 0, sizeof(addr));
67		memcpy(&local_sa, addr2sa(af, &addr, LDP_PORT),
68		    sizeof(local_sa));
69		break;
70	case LDP_SOCKET_EDISC:
71	case LDP_SOCKET_SESSION:
72		addr = (ldp_af_conf_get(ldpd_conf, af))->trans_addr;
73		memcpy(&local_sa, addr2sa(af, &addr, LDP_PORT),
74		    sizeof(local_sa));
75		if (sock_set_bindany(fd, 1) == -1) {
76			close(fd);
77			return (-1);
78		}
79		break;
80	}
81	if (sock_set_reuse(fd, 1) == -1) {
82		close(fd);
83		return (-1);
84	}
85	if (bind(fd, (struct sockaddr *)&local_sa, local_sa.ss_len) == -1) {
86		log_warn("%s: error binding socket", __func__);
87		close(fd);
88		return (-1);
89	}
90
91	/* set options */
92	switch (af) {
93	case AF_INET:
94		if (sock_set_ipv4_tos(fd, IPTOS_PREC_INTERNETCONTROL) == -1) {
95			close(fd);
96			return (-1);
97		}
98		if (type == LDP_SOCKET_DISC) {
99			if (sock_set_ipv4_mcast_ttl(fd,
100			    IP_DEFAULT_MULTICAST_TTL) == -1) {
101				close(fd);
102				return (-1);
103			}
104			if (sock_set_ipv4_mcast_loop(fd) == -1) {
105				close(fd);
106				return (-1);
107			}
108		}
109		if (type == LDP_SOCKET_DISC || type == LDP_SOCKET_EDISC) {
110			if (sock_set_ipv4_recvif(fd, 1) == -1) {
111				close(fd);
112				return (-1);
113			}
114		}
115		if (type == LDP_SOCKET_SESSION) {
116			if (sock_set_ipv4_ucast_ttl(fd, 255) == -1) {
117				close(fd);
118				return (-1);
119			}
120		}
121		break;
122	case AF_INET6:
123		if (sock_set_ipv6_dscp(fd, IPTOS_PREC_INTERNETCONTROL) == -1) {
124			close(fd);
125			return (-1);
126		}
127		if (type == LDP_SOCKET_DISC) {
128			if (sock_set_ipv6_mcast_loop(fd) == -1) {
129				close(fd);
130				return (-1);
131			}
132			if (sock_set_ipv6_mcast_hops(fd, 255) == -1) {
133				close(fd);
134				return (-1);
135			}
136			if (!(ldpd_conf->ipv6.flags & F_LDPD_AF_NO_GTSM)) {
137				if (sock_set_ipv6_minhopcount(fd, 255) == -1) {
138					close(fd);
139					return (-1);
140				}
141			}
142		}
143		if (type == LDP_SOCKET_DISC || type == LDP_SOCKET_EDISC) {
144			if (sock_set_ipv6_pktinfo(fd, 1) == -1) {
145				close(fd);
146				return (-1);
147			}
148		}
149		if (type == LDP_SOCKET_SESSION) {
150			if (sock_set_ipv6_ucast_hops(fd, 255) == -1) {
151				close(fd);
152				return (-1);
153			}
154		}
155		break;
156	}
157	switch (type) {
158	case LDP_SOCKET_DISC:
159	case LDP_SOCKET_EDISC:
160		sock_set_recvbuf(fd);
161		break;
162	case LDP_SOCKET_SESSION:
163		if (listen(fd, LDP_BACKLOG) == -1)
164			log_warn("%s: error listening on socket", __func__);
165
166		opt = 1;
167		if (setsockopt(fd, IPPROTO_TCP, TCP_MD5SIG, &opt,
168		    sizeof(opt)) == -1) {
169			if (errno == ENOPROTOOPT) {	/* system w/o md5sig */
170				log_warnx("md5sig not available, disabling");
171				sysdep.no_md5sig = 1;
172			} else {
173				close(fd);
174				return (-1);
175			}
176		}
177		break;
178	}
179
180	return (fd);
181}
182
183void
184sock_set_recvbuf(int fd)
185{
186	int	bsize;
187
188	bsize = 65535;
189	while (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bsize,
190	    sizeof(bsize)) == -1)
191		bsize /= 2;
192}
193
194int
195sock_set_reuse(int fd, int enable)
196{
197	if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &enable,
198	    sizeof(int)) == -1) {
199		log_warn("%s: error setting SO_REUSEADDR", __func__);
200		return (-1);
201	}
202
203	return (0);
204}
205
206int
207sock_set_bindany(int fd, int enable)
208{
209	if (setsockopt(fd, SOL_SOCKET, SO_BINDANY, &enable,
210	    sizeof(int)) == -1) {
211		log_warn("%s: error setting SO_BINDANY", __func__);
212		return (-1);
213	}
214
215	return (0);
216}
217
218int
219sock_set_ipv4_tos(int fd, int tos)
220{
221	if (setsockopt(fd, IPPROTO_IP, IP_TOS, (int *)&tos, sizeof(tos)) == -1) {
222		log_warn("%s: error setting IP_TOS to 0x%x", __func__, tos);
223		return (-1);
224	}
225
226	return (0);
227}
228
229int
230sock_set_ipv4_recvif(int fd, int enable)
231{
232	if (setsockopt(fd, IPPROTO_IP, IP_RECVIF, &enable,
233	    sizeof(enable)) == -1) {
234		log_warn("%s: error setting IP_RECVIF", __func__);
235		return (-1);
236	}
237	return (0);
238}
239
240int
241sock_set_ipv4_minttl(int fd, int ttl)
242{
243	if (setsockopt(fd, IPPROTO_IP, IP_MINTTL, &ttl, sizeof(ttl)) == -1) {
244		log_warn("%s: error setting IP_MINTTL", __func__);
245		return (-1);
246	}
247
248	return (0);
249}
250
251int
252sock_set_ipv4_ucast_ttl(int fd, int ttl)
253{
254	if (setsockopt(fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)) == -1) {
255		log_warn("%s: error setting IP_TTL", __func__);
256		return (-1);
257	}
258
259	return (0);
260}
261
262int
263sock_set_ipv4_mcast_ttl(int fd, uint8_t ttl)
264{
265	if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL,
266	    (char *)&ttl, sizeof(ttl)) == -1) {
267		log_warn("%s: error setting IP_MULTICAST_TTL to %d",
268		    __func__, ttl);
269		return (-1);
270	}
271
272	return (0);
273}
274
275int
276sock_set_ipv4_mcast(struct iface *iface)
277{
278	in_addr_t		 addr;
279
280	addr = if_get_ipv4_addr(iface);
281
282	if (setsockopt(global.ipv4.ldp_disc_socket, IPPROTO_IP, IP_MULTICAST_IF,
283	    &addr, sizeof(addr)) == -1) {
284		log_warn("%s: error setting IP_MULTICAST_IF, interface %s",
285		    __func__, iface->name);
286		return (-1);
287	}
288
289	return (0);
290}
291
292int
293sock_set_ipv4_mcast_loop(int fd)
294{
295	uint8_t	loop = 0;
296
297	if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP,
298	    (char *)&loop, sizeof(loop)) == -1) {
299		log_warn("%s: error setting IP_MULTICAST_LOOP", __func__);
300		return (-1);
301	}
302
303	return (0);
304}
305
306int
307sock_set_ipv6_dscp(int fd, int dscp)
308{
309	if (setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &dscp,
310	    sizeof(dscp)) == -1) {
311		log_warn("%s: error setting IPV6_TCLASS", __func__);
312		return (-1);
313	}
314
315	return (0);
316}
317
318int
319sock_set_ipv6_pktinfo(int fd, int enable)
320{
321	if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &enable,
322	    sizeof(enable)) == -1) {
323		log_warn("%s: error setting IPV6_RECVPKTINFO", __func__);
324		return (-1);
325	}
326
327	return (0);
328}
329
330int
331sock_set_ipv6_minhopcount(int fd, int hoplimit)
332{
333	if (setsockopt(fd, IPPROTO_IPV6, IPV6_MINHOPCOUNT,
334	    &hoplimit, sizeof(hoplimit)) == -1) {
335		log_warn("%s: error setting IPV6_MINHOPCOUNT", __func__);
336		return (-1);
337	}
338
339	return (0);
340}
341
342int
343sock_set_ipv6_ucast_hops(int fd, int hoplimit)
344{
345	if (setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
346	    &hoplimit, sizeof(hoplimit)) == -1) {
347		log_warn("%s: error setting IPV6_UNICAST_HOPS", __func__);
348		return (-1);
349	}
350
351	return (0);
352}
353
354int
355sock_set_ipv6_mcast_hops(int fd, int hoplimit)
356{
357	if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
358	    &hoplimit, sizeof(hoplimit)) == -1) {
359		log_warn("%s: error setting IPV6_MULTICAST_HOPS", __func__);
360		return (-1);
361	}
362
363	return (0);
364}
365
366int
367sock_set_ipv6_mcast(struct iface *iface)
368{
369	if (setsockopt(global.ipv6.ldp_disc_socket, IPPROTO_IPV6,
370	    IPV6_MULTICAST_IF, &iface->ifindex, sizeof(iface->ifindex)) == -1) {
371		log_warn("%s: error setting IPV6_MULTICAST_IF, interface %s",
372		    __func__, iface->name);
373		return (-1);
374	}
375
376	return (0);
377}
378
379int
380sock_set_ipv6_mcast_loop(int fd)
381{
382	unsigned int	loop = 0;
383
384	if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
385	    &loop, sizeof(loop)) == -1) {
386		log_warn("%s: error setting IPV6_MULTICAST_LOOP", __func__);
387		return (-1);
388	}
389
390	return (0);
391}
392