]> git.proxmox.com Git - mirror_frr.git/blob - ldpd/socket.c
ldpd: changes for code maintainability
[mirror_frr.git] / ldpd / socket.c
1 // SPDX-License-Identifier: ISC
2 /* $OpenBSD$ */
3
4 /*
5 * Copyright (c) 2016 Renato Westphal <renato@openbsd.org>
6 * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
7 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
8 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
9 */
10
11 #include <zebra.h>
12
13 #include "ldpd.h"
14 #include "ldpe.h"
15 #include "log.h"
16
17 #include "lib/log.h"
18 #include "privs.h"
19 #include "sockopt.h"
20
21 extern struct zebra_privs_t ldpd_privs;
22 extern struct zebra_privs_t ldpe_privs;
23
24 int
25 ldp_create_socket(int af, enum socket_type type)
26 {
27 int fd, domain, proto;
28 union ldpd_addr addr;
29 union sockunion local_su;
30 #ifdef __OpenBSD__
31 int opt;
32 #endif
33
34 /* create socket */
35 switch (type) {
36 case LDP_SOCKET_DISC:
37 case LDP_SOCKET_EDISC:
38 domain = SOCK_DGRAM;
39 proto = IPPROTO_UDP;
40 break;
41 case LDP_SOCKET_SESSION:
42 domain = SOCK_STREAM;
43 proto = IPPROTO_TCP;
44 break;
45 default:
46 fatalx("ldp_create_socket: unknown socket type");
47 }
48 fd = socket(af, domain, proto);
49 if (fd == -1) {
50 log_warn("%s: error creating socket", __func__);
51 return (-1);
52 }
53 sock_set_nonblock(fd);
54 sockopt_v6only(af, fd);
55
56 /* bind to a local address/port */
57 switch (type) {
58 case LDP_SOCKET_DISC:
59 /* listen on all addresses */
60 memset(&addr, 0, sizeof(addr));
61 addr2sa(af, &addr, LDP_PORT, &local_su);
62 break;
63 case LDP_SOCKET_EDISC:
64 case LDP_SOCKET_SESSION:
65 addr = (ldp_af_conf_get(ldpd_conf, af))->trans_addr;
66 addr2sa(af, &addr, LDP_PORT, &local_su);
67 /* ignore any possible error */
68 sock_set_bindany(fd, 1);
69 break;
70 }
71 frr_with_privs(&ldpd_privs) {
72 if (sock_set_reuse(fd, 1) == -1) {
73 close(fd);
74 return (-1);
75 }
76 if (bind(fd, &local_su.sa, sockaddr_len(&local_su.sa)) == -1) {
77 log_warnx("%s: error binding socket: %s", __func__,
78 safe_strerror(errno));
79 close(fd);
80 return (-1);
81 }
82 }
83
84 /* set options */
85 switch (af) {
86 case AF_INET:
87 if (sock_set_ipv4_tos(fd, IPTOS_PREC_INTERNETCONTROL) == -1) {
88 close(fd);
89 return (-1);
90 }
91 if (type == LDP_SOCKET_DISC) {
92 if (sock_set_ipv4_mcast_ttl(fd, IP_DEFAULT_MULTICAST_TTL) == -1) {
93 close(fd);
94 return (-1);
95 }
96 if (sock_set_ipv4_mcast_loop(fd) == -1) {
97 close(fd);
98 return (-1);
99 }
100 }
101 if (type == LDP_SOCKET_DISC || type == LDP_SOCKET_EDISC) {
102 if (sock_set_ipv4_recvif(fd, 1) == -1) {
103 close(fd);
104 return (-1);
105 }
106 #ifndef MSG_MCAST
107 #if defined(HAVE_IP_PKTINFO)
108 if (sock_set_ipv4_pktinfo(fd, 1) == -1) {
109 close(fd);
110 return (-1);
111 }
112 #elif defined(HAVE_IP_RECVDSTADDR)
113 if (sock_set_ipv4_recvdstaddr(fd, 1) == -1) {
114 close(fd);
115 return (-1);
116 }
117 #else
118 #error "Unsupported socket API"
119 #endif
120 #endif /* MSG_MCAST */
121 }
122 if (type == LDP_SOCKET_SESSION) {
123 if (sock_set_ipv4_ucast_ttl(fd, 255) == -1) {
124 close(fd);
125 return (-1);
126 }
127 }
128 break;
129 case AF_INET6:
130 if (sock_set_ipv6_dscp(fd, IPTOS_PREC_INTERNETCONTROL) == -1) {
131 close(fd);
132 return (-1);
133 }
134 if (type == LDP_SOCKET_DISC) {
135 if (sock_set_ipv6_mcast_loop(fd) == -1) {
136 close(fd);
137 return (-1);
138 }
139 if (sock_set_ipv6_mcast_hops(fd, 255) == -1) {
140 close(fd);
141 return (-1);
142 }
143 if (!CHECK_FLAG(ldpd_conf->ipv6.flags, F_LDPD_AF_NO_GTSM)) {
144 /* ignore any possible error */
145 sock_set_ipv6_minhopcount(fd, 255);
146 }
147 }
148 if (type == LDP_SOCKET_DISC || type == LDP_SOCKET_EDISC) {
149 if (sock_set_ipv6_pktinfo(fd, 1) == -1) {
150 close(fd);
151 return (-1);
152 }
153 }
154 if (type == LDP_SOCKET_SESSION) {
155 if (sock_set_ipv6_ucast_hops(fd, 255) == -1) {
156 close(fd);
157 return (-1);
158 }
159 }
160 break;
161 }
162 switch (type) {
163 case LDP_SOCKET_DISC:
164 case LDP_SOCKET_EDISC:
165 sock_set_recvbuf(fd);
166 break;
167 case LDP_SOCKET_SESSION:
168 if (listen(fd, LDP_BACKLOG) == -1)
169 log_warn("%s: error listening on socket", __func__);
170
171 #ifdef __OpenBSD__
172 opt = 1;
173 if (setsockopt(fd, IPPROTO_TCP, TCP_MD5SIG, &opt, sizeof(opt)) == -1) {
174 if (errno == ENOPROTOOPT) { /* system w/o md5sig */
175 log_warnx("md5sig not available, disabling");
176 sysdep.no_md5sig = 1;
177 } else {
178 close(fd);
179 return (-1);
180 }
181 }
182 #endif
183 break;
184 }
185
186 return (fd);
187 }
188
189 void
190 sock_set_nonblock(int fd)
191 {
192 int flags;
193
194 if ((flags = fcntl(fd, F_GETFL, 0)) == -1)
195 fatal("fcntl F_GETFL");
196
197 SET_FLAG(flags, O_NONBLOCK);
198
199 if (fcntl(fd, F_SETFL, flags) == -1)
200 fatal("fcntl F_SETFL");
201 }
202
203 void
204 sock_set_cloexec(int fd)
205 {
206 int flags;
207
208 if ((flags = fcntl(fd, F_GETFD, 0)) == -1)
209 fatal("fcntl F_GETFD");
210
211 SET_FLAG(flags, FD_CLOEXEC);
212
213 if (fcntl(fd, F_SETFD, flags) == -1)
214 fatal("fcntl F_SETFD");
215 }
216
217 void
218 sock_set_recvbuf(int fd)
219 {
220 int bsize;
221
222 bsize = 65535;
223 while (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bsize, sizeof(bsize)) == -1)
224 bsize /= 2;
225 }
226
227 int
228 sock_set_reuse(int fd, int enable)
229 {
230 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0) {
231 log_warn("%s: error setting SO_REUSEADDR", __func__);
232 return (-1);
233 }
234
235 return (0);
236 }
237
238 int
239 sock_set_bindany(int fd, int enable)
240 {
241 #ifdef HAVE_SO_BINDANY
242 frr_with_privs(&ldpd_privs) {
243 if (setsockopt(fd, SOL_SOCKET, SO_BINDANY, &enable, sizeof(int)) < 0) {
244 log_warn("%s: error setting SO_BINDANY", __func__);
245 return (-1);
246 }
247 }
248 return (0);
249 #elif defined(HAVE_IP_FREEBIND)
250 if (setsockopt(fd, IPPROTO_IP, IP_FREEBIND, &enable, sizeof(int)) < 0) {
251 log_warn("%s: error setting IP_FREEBIND", __func__);
252 return (-1);
253 }
254 return (0);
255 #elif defined(IP_BINDANY)
256 frr_with_privs(&ldpd_privs) {
257 if (setsockopt(fd, IPPROTO_IP, IP_BINDANY, &enable, sizeof(int)) < 0) {
258 log_warn("%s: error setting IP_BINDANY", __func__);
259 return (-1);
260 }
261 }
262 return (0);
263 #else
264 log_warnx(
265 "%s: missing SO_BINDANY, IP_FREEBIND and IP_BINDANY, unable to bind to a nonlocal IP address",
266 __func__);
267 return (-1);
268 #endif /* HAVE_SO_BINDANY */
269 }
270
271 #ifndef __OpenBSD__
272 /*
273 * Set MD5 key for the socket, for the given peer address. If the password
274 * is NULL or zero-length, the option will be disabled.
275 */
276 int
277 sock_set_md5sig(int fd, int af, union ldpd_addr *addr, const char *password)
278 {
279 int ret = -1;
280 int save_errno = ENOSYS;
281 #if HAVE_DECL_TCP_MD5SIG
282 union sockunion su;
283 #endif
284
285 if (fd == -1)
286 return (0);
287 #if HAVE_DECL_TCP_MD5SIG
288 addr2sa(af, addr, 0, &su);
289
290 frr_with_privs(&ldpe_privs) {
291 ret = sockopt_tcp_signature(fd, &su, password);
292 save_errno = errno;
293 }
294 #endif /* HAVE_TCP_MD5SIG */
295 if (ret < 0)
296 log_warnx("%s: can't set TCP_MD5SIG option on fd %d: %s",
297 __func__, fd, safe_strerror(save_errno));
298
299 return (ret);
300 }
301 #endif
302
303 int
304 sock_set_ipv4_tos(int fd, int tos)
305 {
306 if (setsockopt(fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) < 0) {
307 log_warn("%s: error setting IP_TOS to 0x%x", __func__, tos);
308 return (-1);
309 }
310
311 return (0);
312 }
313
314 int
315 sock_set_ipv4_recvif(int fd, ifindex_t enable)
316 {
317 return (setsockopt_ifindex(AF_INET, fd, enable));
318 }
319
320 int
321 sock_set_ipv4_minttl(int fd, int ttl)
322 {
323 return (sockopt_minttl(AF_INET, fd, ttl));
324 }
325
326 int
327 sock_set_ipv4_ucast_ttl(int fd, int ttl)
328 {
329 if (setsockopt(fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)) < 0) {
330 log_warn("%s: error setting IP_TTL", __func__);
331 return (-1);
332 }
333
334 return (0);
335 }
336
337 int
338 sock_set_ipv4_mcast_ttl(int fd, uint8_t ttl)
339 {
340 if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, (char *)&ttl, sizeof(ttl)) < 0) {
341 log_warn("%s: error setting IP_MULTICAST_TTL to %d", __func__, ttl);
342 return (-1);
343 }
344
345 return (0);
346 }
347
348 #ifndef MSG_MCAST
349 #if defined(HAVE_IP_PKTINFO)
350 int
351 sock_set_ipv4_pktinfo(int fd, int enable)
352 {
353 if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &enable, sizeof(enable)) < 0) {
354 log_warn("%s: error setting IP_PKTINFO", __func__);
355 return (-1);
356 }
357
358 return (0);
359 }
360 #elif defined(HAVE_IP_RECVDSTADDR)
361 int
362 sock_set_ipv4_recvdstaddr(int fd, int enable)
363 {
364 if (setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &enable, sizeof(enable)) < 0) {
365 log_warn("%s: error setting IP_RECVDSTADDR", __func__);
366 return (-1);
367 }
368
369 return (0);
370 }
371 #else
372 #error "Unsupported socket API"
373 #endif
374 #endif /* MSG_MCAST */
375
376 int
377 sock_set_ipv4_mcast(struct iface *iface)
378 {
379 struct in_addr if_addr;
380
381 if_addr.s_addr = if_get_ipv4_addr(iface);
382
383 if (setsockopt_ipv4_multicast_if(global.ipv4.ldp_disc_socket,
384 if_addr, iface->ifindex) < 0) {
385 log_warn("%s: error setting IP_MULTICAST_IF, interface %s",
386 __func__, iface->name);
387 return (-1);
388 }
389
390 return (0);
391 }
392
393 int
394 sock_set_ipv4_mcast_loop(int fd)
395 {
396 return (setsockopt_ipv4_multicast_loop(fd, 0));
397 }
398
399 int
400 sock_set_ipv6_dscp(int fd, int dscp)
401 {
402 if (setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &dscp, sizeof(dscp)) < 0) {
403 log_warn("%s: error setting IPV6_TCLASS", __func__);
404 return (-1);
405 }
406
407 return (0);
408 }
409
410 int
411 sock_set_ipv6_pktinfo(int fd, int enable)
412 {
413 if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &enable, sizeof(enable)) < 0) {
414 log_warn("%s: error setting IPV6_RECVPKTINFO", __func__);
415 return (-1);
416 }
417
418 return (0);
419 }
420
421 int
422 sock_set_ipv6_minhopcount(int fd, int hoplimit)
423 {
424 return (sockopt_minttl(AF_INET6, fd, hoplimit));
425 }
426
427 int
428 sock_set_ipv6_ucast_hops(int fd, int hoplimit)
429 {
430 if (setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
431 &hoplimit, sizeof(hoplimit)) < 0) {
432 log_warn("%s: error setting IPV6_UNICAST_HOPS", __func__);
433 return (-1);
434 }
435
436 return (0);
437 }
438
439 int
440 sock_set_ipv6_mcast_hops(int fd, int hoplimit)
441 {
442 if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
443 &hoplimit, sizeof(hoplimit)) < 0) {
444 log_warn("%s: error setting IPV6_MULTICAST_HOPS", __func__);
445 return (-1);
446 }
447
448 return (0);
449 }
450
451 int
452 sock_set_ipv6_mcast(struct iface *iface)
453 {
454 if (setsockopt(global.ipv6.ldp_disc_socket, IPPROTO_IPV6,
455 IPV6_MULTICAST_IF, &iface->ifindex, sizeof(iface->ifindex)) < 0) {
456 log_warn("%s: error setting IPV6_MULTICAST_IF, interface %s",
457 __func__, iface->name);
458 return (-1);
459 }
460
461 return (0);
462 }
463
464 int
465 sock_set_ipv6_mcast_loop(int fd)
466 {
467 unsigned int loop = 0;
468
469 if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
470 &loop, sizeof(loop)) < 0) {
471 log_warn("%s: error setting IPV6_MULTICAST_LOOP", __func__);
472 return (-1);
473 }
474
475 return (0);
476 }