xref: /openbsd/usr.sbin/ldpd/socket.c (revision df69c215)
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 
34 int
ldp_create_socket(int af,enum socket_type type)35 ldp_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 
183 void
sock_set_recvbuf(int fd)184 sock_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 
194 int
sock_set_reuse(int fd,int enable)195 sock_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 
206 int
sock_set_bindany(int fd,int enable)207 sock_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 
218 int
sock_set_ipv4_tos(int fd,int tos)219 sock_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 
229 int
sock_set_ipv4_recvif(int fd,int enable)230 sock_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 
240 int
sock_set_ipv4_minttl(int fd,int ttl)241 sock_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 
251 int
sock_set_ipv4_ucast_ttl(int fd,int ttl)252 sock_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 
262 int
sock_set_ipv4_mcast_ttl(int fd,uint8_t ttl)263 sock_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 
275 int
sock_set_ipv4_mcast(struct iface * iface)276 sock_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 
292 int
sock_set_ipv4_mcast_loop(int fd)293 sock_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 
306 int
sock_set_ipv6_dscp(int fd,int dscp)307 sock_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 
318 int
sock_set_ipv6_pktinfo(int fd,int enable)319 sock_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 
330 int
sock_set_ipv6_minhopcount(int fd,int hoplimit)331 sock_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 
342 int
sock_set_ipv6_ucast_hops(int fd,int hoplimit)343 sock_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 
354 int
sock_set_ipv6_mcast_hops(int fd,int hoplimit)355 sock_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 
366 int
sock_set_ipv6_mcast(struct iface * iface)367 sock_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 
379 int
sock_set_ipv6_mcast_loop(int fd)380 sock_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