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