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