]> git.proxmox.com Git - mirror_frr.git/blame - ldpd/socket.c
Merge pull request #1567 from donaldsharp/json_fixes
[mirror_frr.git] / ldpd / socket.c
CommitLineData
8429abe0
RW
1/* $OpenBSD$ */
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
eac6e3f0 22#include <zebra.h>
8429abe0
RW
23
24#include "ldpd.h"
25#include "ldpe.h"
26#include "log.h"
27
eac6e3f0
RW
28#include "lib/log.h"
29#include "privs.h"
30#include "sockopt.h"
31
32extern struct zebra_privs_t ldpd_privs;
33extern struct zebra_privs_t ldpe_privs;
34
8429abe0
RW
35int
36ldp_create_socket(int af, enum socket_type type)
37{
38 int fd, domain, proto;
39 union ldpd_addr addr;
40 struct sockaddr_storage local_sa;
eac6e3f0 41#ifdef __OpenBSD__
8429abe0 42 int opt;
eac6e3f0
RW
43#endif
44 int save_errno;
8429abe0
RW
45
46 /* create socket */
47 switch (type) {
48 case LDP_SOCKET_DISC:
49 case LDP_SOCKET_EDISC:
50 domain = SOCK_DGRAM;
51 proto = IPPROTO_UDP;
52 break;
53 case LDP_SOCKET_SESSION:
54 domain = SOCK_STREAM;
55 proto = IPPROTO_TCP;
56 break;
57 default:
58 fatalx("ldp_create_socket: unknown socket type");
59 }
eac6e3f0 60 fd = socket(af, domain, proto);
8429abe0
RW
61 if (fd == -1) {
62 log_warn("%s: error creating socket", __func__);
63 return (-1);
64 }
eac6e3f0
RW
65 sock_set_nonblock(fd);
66 sockopt_v6only(af, fd);
8429abe0
RW
67
68 /* bind to a local address/port */
69 switch (type) {
70 case LDP_SOCKET_DISC:
71 /* listen on all addresses */
72 memset(&addr, 0, sizeof(addr));
73 memcpy(&local_sa, addr2sa(af, &addr, LDP_PORT),
74 sizeof(local_sa));
75 break;
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),
80 sizeof(local_sa));
eac6e3f0
RW
81 /* ignore any possible error */
82 sock_set_bindany(fd, 1);
8429abe0
RW
83 break;
84 }
eac6e3f0
RW
85 if (ldpd_privs.change(ZPRIVS_RAISE))
86 log_warn("%s: could not raise privs", __func__);
8429abe0 87 if (sock_set_reuse(fd, 1) == -1) {
07bc3833
RW
88 if (ldpd_privs.change(ZPRIVS_LOWER))
89 log_warn("%s: could not lower privs", __func__);
8429abe0
RW
90 close(fd);
91 return (-1);
92 }
eac6e3f0
RW
93 if (bind(fd, (struct sockaddr *)&local_sa,
94 sockaddr_len((struct sockaddr *)&local_sa)) == -1) {
95 save_errno = errno;
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));
8429abe0
RW
100 close(fd);
101 return (-1);
102 }
eac6e3f0
RW
103 if (ldpd_privs.change(ZPRIVS_LOWER))
104 log_warn("%s: could not lower privs", __func__);
8429abe0
RW
105
106 /* set options */
107 switch (af) {
108 case AF_INET:
109 if (sock_set_ipv4_tos(fd, IPTOS_PREC_INTERNETCONTROL) == -1) {
110 close(fd);
111 return (-1);
112 }
113 if (type == LDP_SOCKET_DISC) {
114 if (sock_set_ipv4_mcast_ttl(fd,
115 IP_DEFAULT_MULTICAST_TTL) == -1) {
116 close(fd);
117 return (-1);
118 }
119 if (sock_set_ipv4_mcast_loop(fd) == -1) {
120 close(fd);
121 return (-1);
122 }
123 }
124 if (type == LDP_SOCKET_DISC || type == LDP_SOCKET_EDISC) {
125 if (sock_set_ipv4_recvif(fd, 1) == -1) {
126 close(fd);
127 return (-1);
128 }
eac6e3f0
RW
129#ifndef MSG_MCAST
130#if defined(HAVE_IP_PKTINFO)
131 if (sock_set_ipv4_pktinfo(fd, 1) == -1) {
132 close(fd);
133 return (-1);
134 }
135#elif defined(HAVE_IP_RECVDSTADDR)
136 if (sock_set_ipv4_recvdstaddr(fd, 1) == -1) {
137 close(fd);
138 return (-1);
139 }
140#else
141#error "Unsupported socket API"
142#endif
143#endif /* MSG_MCAST */
8429abe0
RW
144 }
145 if (type == LDP_SOCKET_SESSION) {
146 if (sock_set_ipv4_ucast_ttl(fd, 255) == -1) {
147 close(fd);
148 return (-1);
149 }
150 }
151 break;
152 case AF_INET6:
153 if (sock_set_ipv6_dscp(fd, IPTOS_PREC_INTERNETCONTROL) == -1) {
154 close(fd);
155 return (-1);
156 }
157 if (type == LDP_SOCKET_DISC) {
158 if (sock_set_ipv6_mcast_loop(fd) == -1) {
159 close(fd);
160 return (-1);
161 }
162 if (sock_set_ipv6_mcast_hops(fd, 255) == -1) {
163 close(fd);
164 return (-1);
165 }
166 if (!(ldpd_conf->ipv6.flags & F_LDPD_AF_NO_GTSM)) {
eac6e3f0
RW
167 /* ignore any possible error */
168 sock_set_ipv6_minhopcount(fd, 255);
8429abe0
RW
169 }
170 }
171 if (type == LDP_SOCKET_DISC || type == LDP_SOCKET_EDISC) {
172 if (sock_set_ipv6_pktinfo(fd, 1) == -1) {
173 close(fd);
174 return (-1);
175 }
176 }
177 if (type == LDP_SOCKET_SESSION) {
178 if (sock_set_ipv6_ucast_hops(fd, 255) == -1) {
179 close(fd);
180 return (-1);
181 }
182 }
183 break;
184 }
185 switch (type) {
186 case LDP_SOCKET_DISC:
187 case LDP_SOCKET_EDISC:
188 sock_set_recvbuf(fd);
189 break;
190 case LDP_SOCKET_SESSION:
191 if (listen(fd, LDP_BACKLOG) == -1)
192 log_warn("%s: error listening on socket", __func__);
193
eac6e3f0 194#ifdef __OpenBSD__
8429abe0
RW
195 opt = 1;
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;
201 } else {
202 close(fd);
203 return (-1);
204 }
205 }
eac6e3f0 206#endif
8429abe0
RW
207 break;
208 }
209
210 return (fd);
211}
212
eac6e3f0
RW
213void
214sock_set_nonblock(int fd)
215{
216 int flags;
217
218 if ((flags = fcntl(fd, F_GETFL, 0)) == -1)
219 fatal("fcntl F_GETFL");
220
221 flags |= O_NONBLOCK;
222
223 if ((flags = fcntl(fd, F_SETFL, flags)) == -1)
224 fatal("fcntl F_SETFL");
225}
226
227void
228sock_set_cloexec(int fd)
229{
230 int flags;
231
232 if ((flags = fcntl(fd, F_GETFD, 0)) == -1)
233 fatal("fcntl F_GETFD");
234
235 flags |= FD_CLOEXEC;
236
237 if ((flags = fcntl(fd, F_SETFD, flags)) == -1)
238 fatal("fcntl F_SETFD");
239}
240
8429abe0
RW
241void
242sock_set_recvbuf(int fd)
243{
244 int bsize;
245
246 bsize = 65535;
247 while (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bsize,
248 sizeof(bsize)) == -1)
249 bsize /= 2;
250}
251
252int
253sock_set_reuse(int fd, int enable)
254{
255 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &enable,
256 sizeof(int)) < 0) {
257 log_warn("%s: error setting SO_REUSEADDR", __func__);
258 return (-1);
259 }
260
261 return (0);
262}
263
264int
265sock_set_bindany(int fd, int enable)
266{
eac6e3f0
RW
267#ifdef HAVE_SO_BINDANY
268 if (ldpd_privs.change(ZPRIVS_RAISE))
269 log_warn("%s: could not raise privs", __func__);
8429abe0
RW
270 if (setsockopt(fd, SOL_SOCKET, SO_BINDANY, &enable,
271 sizeof(int)) < 0) {
eac6e3f0
RW
272 if (ldpd_privs.change(ZPRIVS_LOWER))
273 log_warn("%s: could not lower privs", __func__);
8429abe0
RW
274 log_warn("%s: error setting SO_BINDANY", __func__);
275 return (-1);
276 }
eac6e3f0
RW
277 if (ldpd_privs.change(ZPRIVS_LOWER))
278 log_warn("%s: could not lower privs", __func__);
279 return (0);
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__);
283 return (-1);
284 }
8429abe0 285 return (0);
eac6e3f0
RW
286#else
287 log_warnx("%s: missing SO_BINDANY and IP_FREEBIND, unable to bind "
288 "to a nonlocal IP address", __func__);
289 return (-1);
290#endif /* HAVE_SO_BINDANY */
291}
292
293#ifndef __OpenBSD__
294/*
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.
297 */
298int
299sock_set_md5sig(int fd, int af, union ldpd_addr *addr, const char *password)
300{
301 int ret = -1;
302 int save_errno = ENOSYS;
303#if HAVE_DECL_TCP_MD5SIG
304 union sockunion su;
305#endif
306
307 if (fd == -1)
308 return (0);
309#if HAVE_DECL_TCP_MD5SIG
310 memcpy(&su, addr2sa(af, addr, 0), sizeof(su));
311
312 if (ldpe_privs.change(ZPRIVS_RAISE)) {
313 log_warn("%s: could not raise privs", __func__);
314 return (-1);
315 }
316 ret = sockopt_tcp_signature(fd, &su, password);
317 save_errno = errno;
318 if (ldpe_privs.change(ZPRIVS_LOWER))
319 log_warn("%s: could not lower privs", __func__);
320#endif /* HAVE_TCP_MD5SIG */
321 if (ret < 0)
322 log_warnx("%s: can't set TCP_MD5SIG option on fd %d: %s",
323 __func__, fd, safe_strerror(save_errno));
324
325 return (ret);
8429abe0 326}
eac6e3f0 327#endif
8429abe0
RW
328
329int
330sock_set_ipv4_tos(int fd, int tos)
331{
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);
334 return (-1);
335 }
336
337 return (0);
338}
339
340int
341sock_set_ipv4_recvif(int fd, int enable)
342{
eac6e3f0 343 return (setsockopt_ifindex(AF_INET, fd, enable));
8429abe0
RW
344}
345
346int
347sock_set_ipv4_minttl(int fd, int ttl)
348{
eac6e3f0 349 return (sockopt_minttl(AF_INET, fd, ttl));
8429abe0
RW
350}
351
352int
353sock_set_ipv4_ucast_ttl(int fd, int ttl)
354{
355 if (setsockopt(fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)) < 0) {
356 log_warn("%s: error setting IP_TTL", __func__);
357 return (-1);
358 }
359
360 return (0);
361}
362
363int
364sock_set_ipv4_mcast_ttl(int fd, uint8_t ttl)
365{
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",
369 __func__, ttl);
370 return (-1);
371 }
372
373 return (0);
374}
375
eac6e3f0
RW
376#ifndef MSG_MCAST
377#if defined(HAVE_IP_PKTINFO)
378int
379sock_set_ipv4_pktinfo(int fd, int enable)
380{
381 if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &enable,
382 sizeof(enable)) < 0) {
383 log_warn("%s: error setting IP_PKTINFO", __func__);
384 return (-1);
385 }
386
387 return (0);
388}
389#elif defined(HAVE_IP_RECVDSTADDR)
390int
391sock_set_ipv4_recvdstaddr(int fd, int enable)
392{
393 if (setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &enable,
394 sizeof(enable)) < 0) {
395 log_warn("%s: error setting IP_RECVDSTADDR", __func__);
396 return (-1);
397 }
398
399 return (0);
400}
401#else
402#error "Unsupported socket API"
403#endif
404#endif /* MSG_MCAST */
405
8429abe0
RW
406int
407sock_set_ipv4_mcast(struct iface *iface)
408{
eac6e3f0 409 struct in_addr if_addr;
8429abe0 410
eac6e3f0 411 if_addr.s_addr = if_get_ipv4_addr(iface);
8429abe0 412
eac6e3f0
RW
413 if (setsockopt_ipv4_multicast_if(global.ipv4.ldp_disc_socket,
414 if_addr, iface->ifindex) < 0) {
8429abe0
RW
415 log_warn("%s: error setting IP_MULTICAST_IF, interface %s",
416 __func__, iface->name);
417 return (-1);
418 }
419
420 return (0);
421}
422
423int
424sock_set_ipv4_mcast_loop(int fd)
425{
c5bdb09f 426 return (setsockopt_ipv4_multicast_loop(fd, 0));
8429abe0
RW
427}
428
429int
430sock_set_ipv6_dscp(int fd, int dscp)
431{
432 if (setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &dscp,
433 sizeof(dscp)) < 0) {
434 log_warn("%s: error setting IPV6_TCLASS", __func__);
435 return (-1);
436 }
437
438 return (0);
439}
440
441int
442sock_set_ipv6_pktinfo(int fd, int enable)
443{
444 if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &enable,
445 sizeof(enable)) < 0) {
446 log_warn("%s: error setting IPV6_RECVPKTINFO", __func__);
447 return (-1);
448 }
449
450 return (0);
451}
452
453int
454sock_set_ipv6_minhopcount(int fd, int hoplimit)
455{
eac6e3f0 456 return (sockopt_minttl(AF_INET6, fd, hoplimit));
8429abe0
RW
457}
458
459int
460sock_set_ipv6_ucast_hops(int fd, int hoplimit)
461{
462 if (setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
463 &hoplimit, sizeof(hoplimit)) < 0) {
464 log_warn("%s: error setting IPV6_UNICAST_HOPS", __func__);
465 return (-1);
466 }
467
468 return (0);
469}
470
471int
472sock_set_ipv6_mcast_hops(int fd, int hoplimit)
473{
474 if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
475 &hoplimit, sizeof(hoplimit)) < 0) {
476 log_warn("%s: error setting IPV6_MULTICAST_HOPS", __func__);
477 return (-1);
478 }
479
480 return (0);
481}
482
483int
484sock_set_ipv6_mcast(struct iface *iface)
485{
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);
490 return (-1);
491 }
492
493 return (0);
494}
495
496int
497sock_set_ipv6_mcast_loop(int fd)
498{
499 unsigned int loop = 0;
500
501 if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
502 &loop, sizeof(loop)) < 0) {
503 log_warn("%s: error setting IPV6_MULTICAST_LOOP", __func__);
504 return (-1);
505 }
506
507 return (0);
508}