]> git.proxmox.com Git - mirror_frr.git/blob - ldpd/socket.c
Merge branch 'stable/2.0'
[mirror_frr.git] / ldpd / socket.c
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
22 #include <zebra.h>
23
24 #include "ldpd.h"
25 #include "ldpe.h"
26 #include "log.h"
27
28 #include "lib/log.h"
29 #include "privs.h"
30 #include "sockopt.h"
31
32 extern struct zebra_privs_t ldpd_privs;
33 extern struct zebra_privs_t ldpe_privs;
34
35 int
36 ldp_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;
41 #ifdef __OpenBSD__
42 int opt;
43 #endif
44 int save_errno;
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 }
60 fd = socket(af, domain, proto);
61 if (fd == -1) {
62 log_warn("%s: error creating socket", __func__);
63 return (-1);
64 }
65 sock_set_nonblock(fd);
66 sockopt_v6only(af, fd);
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));
81 /* ignore any possible error */
82 sock_set_bindany(fd, 1);
83 break;
84 }
85 if (ldpd_privs.change(ZPRIVS_RAISE))
86 log_warn("%s: could not raise privs", __func__);
87 if (sock_set_reuse(fd, 1) == -1) {
88 if (ldpd_privs.change(ZPRIVS_LOWER))
89 log_warn("%s: could not lower privs", __func__);
90 close(fd);
91 return (-1);
92 }
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));
100 close(fd);
101 return (-1);
102 }
103 if (ldpd_privs.change(ZPRIVS_LOWER))
104 log_warn("%s: could not lower privs", __func__);
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 }
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 */
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)) {
167 /* ignore any possible error */
168 sock_set_ipv6_minhopcount(fd, 255);
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
194 #ifdef __OpenBSD__
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 }
206 #endif
207 break;
208 }
209
210 return (fd);
211 }
212
213 void
214 sock_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
227 void
228 sock_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
241 void
242 sock_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
252 int
253 sock_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
264 int
265 sock_set_bindany(int fd, int enable)
266 {
267 #ifdef HAVE_SO_BINDANY
268 if (ldpd_privs.change(ZPRIVS_RAISE))
269 log_warn("%s: could not raise privs", __func__);
270 if (setsockopt(fd, SOL_SOCKET, SO_BINDANY, &enable,
271 sizeof(int)) < 0) {
272 if (ldpd_privs.change(ZPRIVS_LOWER))
273 log_warn("%s: could not lower privs", __func__);
274 log_warn("%s: error setting SO_BINDANY", __func__);
275 return (-1);
276 }
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 }
285 return (0);
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 */
298 int
299 sock_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);
326 }
327 #endif
328
329 int
330 sock_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
340 int
341 sock_set_ipv4_recvif(int fd, int enable)
342 {
343 return (setsockopt_ifindex(AF_INET, fd, enable));
344 }
345
346 int
347 sock_set_ipv4_minttl(int fd, int ttl)
348 {
349 return (sockopt_minttl(AF_INET, fd, ttl));
350 }
351
352 int
353 sock_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
363 int
364 sock_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
376 #ifndef MSG_MCAST
377 #if defined(HAVE_IP_PKTINFO)
378 int
379 sock_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)
390 int
391 sock_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
406 int
407 sock_set_ipv4_mcast(struct iface *iface)
408 {
409 struct in_addr if_addr;
410
411 if_addr.s_addr = if_get_ipv4_addr(iface);
412
413 if (setsockopt_ipv4_multicast_if(global.ipv4.ldp_disc_socket,
414 if_addr, iface->ifindex) < 0) {
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
423 int
424 sock_set_ipv4_mcast_loop(int fd)
425 {
426 return (setsockopt_ipv4_multicast_loop(fd, 0));
427 }
428
429 int
430 sock_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
441 int
442 sock_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
453 int
454 sock_set_ipv6_minhopcount(int fd, int hoplimit)
455 {
456 return (sockopt_minttl(AF_INET6, fd, hoplimit));
457 }
458
459 int
460 sock_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
471 int
472 sock_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
483 int
484 sock_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
496 int
497 sock_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 }