]> git.proxmox.com Git - mirror_frr.git/blame - ldpd/socket.c
ldpd: adapt the code for Quagga
[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
RW
87 if (sock_set_reuse(fd, 1) == -1) {
88 close(fd);
89 return (-1);
90 }
eac6e3f0
RW
91 if (bind(fd, (struct sockaddr *)&local_sa,
92 sockaddr_len((struct sockaddr *)&local_sa)) == -1) {
93 save_errno = errno;
94 if (ldpd_privs.change(ZPRIVS_LOWER))
95 log_warn("%s: could not lower privs", __func__);
96 log_warnx("%s: error binding socket: %s", __func__,
97 safe_strerror(save_errno));
8429abe0
RW
98 close(fd);
99 return (-1);
100 }
eac6e3f0
RW
101 if (ldpd_privs.change(ZPRIVS_LOWER))
102 log_warn("%s: could not lower privs", __func__);
8429abe0
RW
103
104 /* set options */
105 switch (af) {
106 case AF_INET:
107 if (sock_set_ipv4_tos(fd, IPTOS_PREC_INTERNETCONTROL) == -1) {
108 close(fd);
109 return (-1);
110 }
111 if (type == LDP_SOCKET_DISC) {
112 if (sock_set_ipv4_mcast_ttl(fd,
113 IP_DEFAULT_MULTICAST_TTL) == -1) {
114 close(fd);
115 return (-1);
116 }
117 if (sock_set_ipv4_mcast_loop(fd) == -1) {
118 close(fd);
119 return (-1);
120 }
121 }
122 if (type == LDP_SOCKET_DISC || type == LDP_SOCKET_EDISC) {
123 if (sock_set_ipv4_recvif(fd, 1) == -1) {
124 close(fd);
125 return (-1);
126 }
eac6e3f0
RW
127#ifndef MSG_MCAST
128#if defined(HAVE_IP_PKTINFO)
129 if (sock_set_ipv4_pktinfo(fd, 1) == -1) {
130 close(fd);
131 return (-1);
132 }
133#elif defined(HAVE_IP_RECVDSTADDR)
134 if (sock_set_ipv4_recvdstaddr(fd, 1) == -1) {
135 close(fd);
136 return (-1);
137 }
138#else
139#error "Unsupported socket API"
140#endif
141#endif /* MSG_MCAST */
8429abe0
RW
142 }
143 if (type == LDP_SOCKET_SESSION) {
144 if (sock_set_ipv4_ucast_ttl(fd, 255) == -1) {
145 close(fd);
146 return (-1);
147 }
148 }
149 break;
150 case AF_INET6:
151 if (sock_set_ipv6_dscp(fd, IPTOS_PREC_INTERNETCONTROL) == -1) {
152 close(fd);
153 return (-1);
154 }
155 if (type == LDP_SOCKET_DISC) {
156 if (sock_set_ipv6_mcast_loop(fd) == -1) {
157 close(fd);
158 return (-1);
159 }
160 if (sock_set_ipv6_mcast_hops(fd, 255) == -1) {
161 close(fd);
162 return (-1);
163 }
164 if (!(ldpd_conf->ipv6.flags & F_LDPD_AF_NO_GTSM)) {
eac6e3f0
RW
165 /* ignore any possible error */
166 sock_set_ipv6_minhopcount(fd, 255);
8429abe0
RW
167 }
168 }
169 if (type == LDP_SOCKET_DISC || type == LDP_SOCKET_EDISC) {
170 if (sock_set_ipv6_pktinfo(fd, 1) == -1) {
171 close(fd);
172 return (-1);
173 }
174 }
175 if (type == LDP_SOCKET_SESSION) {
176 if (sock_set_ipv6_ucast_hops(fd, 255) == -1) {
177 close(fd);
178 return (-1);
179 }
180 }
181 break;
182 }
183 switch (type) {
184 case LDP_SOCKET_DISC:
185 case LDP_SOCKET_EDISC:
186 sock_set_recvbuf(fd);
187 break;
188 case LDP_SOCKET_SESSION:
189 if (listen(fd, LDP_BACKLOG) == -1)
190 log_warn("%s: error listening on socket", __func__);
191
eac6e3f0 192#ifdef __OpenBSD__
8429abe0
RW
193 opt = 1;
194 if (setsockopt(fd, IPPROTO_TCP, TCP_MD5SIG, &opt,
195 sizeof(opt)) == -1) {
196 if (errno == ENOPROTOOPT) { /* system w/o md5sig */
197 log_warnx("md5sig not available, disabling");
198 sysdep.no_md5sig = 1;
199 } else {
200 close(fd);
201 return (-1);
202 }
203 }
eac6e3f0 204#endif
8429abe0
RW
205 break;
206 }
207
208 return (fd);
209}
210
eac6e3f0
RW
211void
212sock_set_nonblock(int fd)
213{
214 int flags;
215
216 if ((flags = fcntl(fd, F_GETFL, 0)) == -1)
217 fatal("fcntl F_GETFL");
218
219 flags |= O_NONBLOCK;
220
221 if ((flags = fcntl(fd, F_SETFL, flags)) == -1)
222 fatal("fcntl F_SETFL");
223}
224
225void
226sock_set_cloexec(int fd)
227{
228 int flags;
229
230 if ((flags = fcntl(fd, F_GETFD, 0)) == -1)
231 fatal("fcntl F_GETFD");
232
233 flags |= FD_CLOEXEC;
234
235 if ((flags = fcntl(fd, F_SETFD, flags)) == -1)
236 fatal("fcntl F_SETFD");
237}
238
8429abe0
RW
239void
240sock_set_recvbuf(int fd)
241{
242 int bsize;
243
244 bsize = 65535;
245 while (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bsize,
246 sizeof(bsize)) == -1)
247 bsize /= 2;
248}
249
250int
251sock_set_reuse(int fd, int enable)
252{
253 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &enable,
254 sizeof(int)) < 0) {
255 log_warn("%s: error setting SO_REUSEADDR", __func__);
256 return (-1);
257 }
258
259 return (0);
260}
261
262int
263sock_set_bindany(int fd, int enable)
264{
eac6e3f0
RW
265#ifdef HAVE_SO_BINDANY
266 if (ldpd_privs.change(ZPRIVS_RAISE))
267 log_warn("%s: could not raise privs", __func__);
8429abe0
RW
268 if (setsockopt(fd, SOL_SOCKET, SO_BINDANY, &enable,
269 sizeof(int)) < 0) {
eac6e3f0
RW
270 if (ldpd_privs.change(ZPRIVS_LOWER))
271 log_warn("%s: could not lower privs", __func__);
8429abe0
RW
272 log_warn("%s: error setting SO_BINDANY", __func__);
273 return (-1);
274 }
eac6e3f0
RW
275 if (ldpd_privs.change(ZPRIVS_LOWER))
276 log_warn("%s: could not lower privs", __func__);
277 return (0);
278#elif defined(HAVE_IP_FREEBIND)
279 if (setsockopt(fd, IPPROTO_IP, IP_FREEBIND, &enable, sizeof(int)) < 0) {
280 log_warn("%s: error setting IP_FREEBIND", __func__);
281 return (-1);
282 }
8429abe0 283 return (0);
eac6e3f0
RW
284#else
285 log_warnx("%s: missing SO_BINDANY and IP_FREEBIND, unable to bind "
286 "to a nonlocal IP address", __func__);
287 return (-1);
288#endif /* HAVE_SO_BINDANY */
289}
290
291#ifndef __OpenBSD__
292/*
293 * Set MD5 key for the socket, for the given peer address. If the password
294 * is NULL or zero-length, the option will be disabled.
295 */
296int
297sock_set_md5sig(int fd, int af, union ldpd_addr *addr, const char *password)
298{
299 int ret = -1;
300 int save_errno = ENOSYS;
301#if HAVE_DECL_TCP_MD5SIG
302 union sockunion su;
303#endif
304
305 if (fd == -1)
306 return (0);
307#if HAVE_DECL_TCP_MD5SIG
308 memcpy(&su, addr2sa(af, addr, 0), sizeof(su));
309
310 if (ldpe_privs.change(ZPRIVS_RAISE)) {
311 log_warn("%s: could not raise privs", __func__);
312 return (-1);
313 }
314 ret = sockopt_tcp_signature(fd, &su, password);
315 save_errno = errno;
316 if (ldpe_privs.change(ZPRIVS_LOWER))
317 log_warn("%s: could not lower privs", __func__);
318#endif /* HAVE_TCP_MD5SIG */
319 if (ret < 0)
320 log_warnx("%s: can't set TCP_MD5SIG option on fd %d: %s",
321 __func__, fd, safe_strerror(save_errno));
322
323 return (ret);
8429abe0 324}
eac6e3f0 325#endif
8429abe0
RW
326
327int
328sock_set_ipv4_tos(int fd, int tos)
329{
330 if (setsockopt(fd, IPPROTO_IP, IP_TOS, (int *)&tos, sizeof(tos)) < 0) {
331 log_warn("%s: error setting IP_TOS to 0x%x", __func__, tos);
332 return (-1);
333 }
334
335 return (0);
336}
337
338int
339sock_set_ipv4_recvif(int fd, int enable)
340{
eac6e3f0 341 return (setsockopt_ifindex(AF_INET, fd, enable));
8429abe0
RW
342}
343
344int
345sock_set_ipv4_minttl(int fd, int ttl)
346{
eac6e3f0 347 return (sockopt_minttl(AF_INET, fd, ttl));
8429abe0
RW
348}
349
350int
351sock_set_ipv4_ucast_ttl(int fd, int ttl)
352{
353 if (setsockopt(fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)) < 0) {
354 log_warn("%s: error setting IP_TTL", __func__);
355 return (-1);
356 }
357
358 return (0);
359}
360
361int
362sock_set_ipv4_mcast_ttl(int fd, uint8_t ttl)
363{
364 if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL,
365 (char *)&ttl, sizeof(ttl)) < 0) {
366 log_warn("%s: error setting IP_MULTICAST_TTL to %d",
367 __func__, ttl);
368 return (-1);
369 }
370
371 return (0);
372}
373
eac6e3f0
RW
374#ifndef MSG_MCAST
375#if defined(HAVE_IP_PKTINFO)
376int
377sock_set_ipv4_pktinfo(int fd, int enable)
378{
379 if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &enable,
380 sizeof(enable)) < 0) {
381 log_warn("%s: error setting IP_PKTINFO", __func__);
382 return (-1);
383 }
384
385 return (0);
386}
387#elif defined(HAVE_IP_RECVDSTADDR)
388int
389sock_set_ipv4_recvdstaddr(int fd, int enable)
390{
391 if (setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &enable,
392 sizeof(enable)) < 0) {
393 log_warn("%s: error setting IP_RECVDSTADDR", __func__);
394 return (-1);
395 }
396
397 return (0);
398}
399#else
400#error "Unsupported socket API"
401#endif
402#endif /* MSG_MCAST */
403
8429abe0
RW
404int
405sock_set_ipv4_mcast(struct iface *iface)
406{
eac6e3f0 407 struct in_addr if_addr;
8429abe0 408
eac6e3f0 409 if_addr.s_addr = if_get_ipv4_addr(iface);
8429abe0 410
eac6e3f0
RW
411 if (setsockopt_ipv4_multicast_if(global.ipv4.ldp_disc_socket,
412 if_addr, iface->ifindex) < 0) {
8429abe0
RW
413 log_warn("%s: error setting IP_MULTICAST_IF, interface %s",
414 __func__, iface->name);
415 return (-1);
416 }
417
418 return (0);
419}
420
421int
422sock_set_ipv4_mcast_loop(int fd)
423{
424 uint8_t loop = 0;
425
426 if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP,
427 (char *)&loop, sizeof(loop)) < 0) {
428 log_warn("%s: error setting IP_MULTICAST_LOOP", __func__);
429 return (-1);
430 }
431
432 return (0);
433}
434
435int
436sock_set_ipv6_dscp(int fd, int dscp)
437{
438 if (setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &dscp,
439 sizeof(dscp)) < 0) {
440 log_warn("%s: error setting IPV6_TCLASS", __func__);
441 return (-1);
442 }
443
444 return (0);
445}
446
447int
448sock_set_ipv6_pktinfo(int fd, int enable)
449{
450 if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &enable,
451 sizeof(enable)) < 0) {
452 log_warn("%s: error setting IPV6_RECVPKTINFO", __func__);
453 return (-1);
454 }
455
456 return (0);
457}
458
459int
460sock_set_ipv6_minhopcount(int fd, int hoplimit)
461{
eac6e3f0 462 return (sockopt_minttl(AF_INET6, fd, hoplimit));
8429abe0
RW
463}
464
465int
466sock_set_ipv6_ucast_hops(int fd, int hoplimit)
467{
468 if (setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
469 &hoplimit, sizeof(hoplimit)) < 0) {
470 log_warn("%s: error setting IPV6_UNICAST_HOPS", __func__);
471 return (-1);
472 }
473
474 return (0);
475}
476
477int
478sock_set_ipv6_mcast_hops(int fd, int hoplimit)
479{
480 if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
481 &hoplimit, sizeof(hoplimit)) < 0) {
482 log_warn("%s: error setting IPV6_MULTICAST_HOPS", __func__);
483 return (-1);
484 }
485
486 return (0);
487}
488
489int
490sock_set_ipv6_mcast(struct iface *iface)
491{
492 if (setsockopt(global.ipv6.ldp_disc_socket, IPPROTO_IPV6,
493 IPV6_MULTICAST_IF, &iface->ifindex, sizeof(iface->ifindex)) < 0) {
494 log_warn("%s: error setting IPV6_MULTICAST_IF, interface %s",
495 __func__, iface->name);
496 return (-1);
497 }
498
499 return (0);
500}
501
502int
503sock_set_ipv6_mcast_loop(int fd)
504{
505 unsigned int loop = 0;
506
507 if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
508 &loop, sizeof(loop)) < 0) {
509 log_warn("%s: error setting IPV6_MULTICAST_LOOP", __func__);
510 return (-1);
511 }
512
513 return (0);
514}