1 /* $OpenBSD: socket.c,v 1.10 2019/06/28 13:32:48 deraadt Exp $ */
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 <sys/types.h>
23 #include <netinet/in.h>
24 #include <netinet/ip.h>
25 #include <netinet/tcp.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include <errno.h>
29
30 #include "ldpd.h"
31 #include "ldpe.h"
32 #include "log.h"
33
34 int
ldp_create_socket(int af,enum socket_type type)35 ldp_create_socket(int af, enum socket_type type)
36 {
37 int fd, domain, proto;
38 union ldpd_addr addr;
39 struct sockaddr_storage local_sa;
40 int opt;
41
42 /* create socket */
43 switch (type) {
44 case LDP_SOCKET_DISC:
45 case LDP_SOCKET_EDISC:
46 domain = SOCK_DGRAM;
47 proto = IPPROTO_UDP;
48 break;
49 case LDP_SOCKET_SESSION:
50 domain = SOCK_STREAM;
51 proto = IPPROTO_TCP;
52 break;
53 default:
54 fatalx("ldp_create_socket: unknown socket type");
55 }
56 fd = socket(af, domain | SOCK_NONBLOCK | SOCK_CLOEXEC, proto);
57 if (fd == -1) {
58 log_warn("%s: error creating socket", __func__);
59 return (-1);
60 }
61
62 /* bind to a local address/port */
63 switch (type) {
64 case LDP_SOCKET_DISC:
65 /* listen on all addresses */
66 memset(&addr, 0, sizeof(addr));
67 memcpy(&local_sa, addr2sa(af, &addr, LDP_PORT),
68 sizeof(local_sa));
69 break;
70 case LDP_SOCKET_EDISC:
71 case LDP_SOCKET_SESSION:
72 addr = (ldp_af_conf_get(ldpd_conf, af))->trans_addr;
73 memcpy(&local_sa, addr2sa(af, &addr, LDP_PORT),
74 sizeof(local_sa));
75 if (sock_set_bindany(fd, 1) == -1) {
76 close(fd);
77 return (-1);
78 }
79 break;
80 }
81 if (sock_set_reuse(fd, 1) == -1) {
82 close(fd);
83 return (-1);
84 }
85 if (bind(fd, (struct sockaddr *)&local_sa, local_sa.ss_len) == -1) {
86 log_warn("%s: error binding socket", __func__);
87 close(fd);
88 return (-1);
89 }
90
91 /* set options */
92 switch (af) {
93 case AF_INET:
94 if (sock_set_ipv4_tos(fd, IPTOS_PREC_INTERNETCONTROL) == -1) {
95 close(fd);
96 return (-1);
97 }
98 if (type == LDP_SOCKET_DISC) {
99 if (sock_set_ipv4_mcast_ttl(fd,
100 IP_DEFAULT_MULTICAST_TTL) == -1) {
101 close(fd);
102 return (-1);
103 }
104 if (sock_set_ipv4_mcast_loop(fd) == -1) {
105 close(fd);
106 return (-1);
107 }
108 }
109 if (type == LDP_SOCKET_DISC || type == LDP_SOCKET_EDISC) {
110 if (sock_set_ipv4_recvif(fd, 1) == -1) {
111 close(fd);
112 return (-1);
113 }
114 }
115 if (type == LDP_SOCKET_SESSION) {
116 if (sock_set_ipv4_ucast_ttl(fd, 255) == -1) {
117 close(fd);
118 return (-1);
119 }
120 }
121 break;
122 case AF_INET6:
123 if (sock_set_ipv6_dscp(fd, IPTOS_PREC_INTERNETCONTROL) == -1) {
124 close(fd);
125 return (-1);
126 }
127 if (type == LDP_SOCKET_DISC) {
128 if (sock_set_ipv6_mcast_loop(fd) == -1) {
129 close(fd);
130 return (-1);
131 }
132 if (sock_set_ipv6_mcast_hops(fd, 255) == -1) {
133 close(fd);
134 return (-1);
135 }
136 if (!(ldpd_conf->ipv6.flags & F_LDPD_AF_NO_GTSM)) {
137 if (sock_set_ipv6_minhopcount(fd, 255) == -1) {
138 close(fd);
139 return (-1);
140 }
141 }
142 }
143 if (type == LDP_SOCKET_DISC || type == LDP_SOCKET_EDISC) {
144 if (sock_set_ipv6_pktinfo(fd, 1) == -1) {
145 close(fd);
146 return (-1);
147 }
148 }
149 if (type == LDP_SOCKET_SESSION) {
150 if (sock_set_ipv6_ucast_hops(fd, 255) == -1) {
151 close(fd);
152 return (-1);
153 }
154 }
155 break;
156 }
157 switch (type) {
158 case LDP_SOCKET_DISC:
159 case LDP_SOCKET_EDISC:
160 sock_set_recvbuf(fd);
161 break;
162 case LDP_SOCKET_SESSION:
163 if (listen(fd, LDP_BACKLOG) == -1)
164 log_warn("%s: error listening on socket", __func__);
165
166 opt = 1;
167 if (setsockopt(fd, IPPROTO_TCP, TCP_MD5SIG, &opt,
168 sizeof(opt)) == -1) {
169 if (errno == ENOPROTOOPT) { /* system w/o md5sig */
170 log_warnx("md5sig not available, disabling");
171 sysdep.no_md5sig = 1;
172 } else {
173 close(fd);
174 return (-1);
175 }
176 }
177 break;
178 }
179
180 return (fd);
181 }
182
183 void
sock_set_recvbuf(int fd)184 sock_set_recvbuf(int fd)
185 {
186 int bsize;
187
188 bsize = 65535;
189 while (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bsize,
190 sizeof(bsize)) == -1)
191 bsize /= 2;
192 }
193
194 int
sock_set_reuse(int fd,int enable)195 sock_set_reuse(int fd, int enable)
196 {
197 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &enable,
198 sizeof(int)) == -1) {
199 log_warn("%s: error setting SO_REUSEADDR", __func__);
200 return (-1);
201 }
202
203 return (0);
204 }
205
206 int
sock_set_bindany(int fd,int enable)207 sock_set_bindany(int fd, int enable)
208 {
209 if (setsockopt(fd, SOL_SOCKET, SO_BINDANY, &enable,
210 sizeof(int)) == -1) {
211 log_warn("%s: error setting SO_BINDANY", __func__);
212 return (-1);
213 }
214
215 return (0);
216 }
217
218 int
sock_set_ipv4_tos(int fd,int tos)219 sock_set_ipv4_tos(int fd, int tos)
220 {
221 if (setsockopt(fd, IPPROTO_IP, IP_TOS, (int *)&tos, sizeof(tos)) == -1) {
222 log_warn("%s: error setting IP_TOS to 0x%x", __func__, tos);
223 return (-1);
224 }
225
226 return (0);
227 }
228
229 int
sock_set_ipv4_recvif(int fd,int enable)230 sock_set_ipv4_recvif(int fd, int enable)
231 {
232 if (setsockopt(fd, IPPROTO_IP, IP_RECVIF, &enable,
233 sizeof(enable)) == -1) {
234 log_warn("%s: error setting IP_RECVIF", __func__);
235 return (-1);
236 }
237 return (0);
238 }
239
240 int
sock_set_ipv4_minttl(int fd,int ttl)241 sock_set_ipv4_minttl(int fd, int ttl)
242 {
243 if (setsockopt(fd, IPPROTO_IP, IP_MINTTL, &ttl, sizeof(ttl)) == -1) {
244 log_warn("%s: error setting IP_MINTTL", __func__);
245 return (-1);
246 }
247
248 return (0);
249 }
250
251 int
sock_set_ipv4_ucast_ttl(int fd,int ttl)252 sock_set_ipv4_ucast_ttl(int fd, int ttl)
253 {
254 if (setsockopt(fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)) == -1) {
255 log_warn("%s: error setting IP_TTL", __func__);
256 return (-1);
257 }
258
259 return (0);
260 }
261
262 int
sock_set_ipv4_mcast_ttl(int fd,uint8_t ttl)263 sock_set_ipv4_mcast_ttl(int fd, uint8_t ttl)
264 {
265 if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL,
266 (char *)&ttl, sizeof(ttl)) == -1) {
267 log_warn("%s: error setting IP_MULTICAST_TTL to %d",
268 __func__, ttl);
269 return (-1);
270 }
271
272 return (0);
273 }
274
275 int
sock_set_ipv4_mcast(struct iface * iface)276 sock_set_ipv4_mcast(struct iface *iface)
277 {
278 in_addr_t addr;
279
280 addr = if_get_ipv4_addr(iface);
281
282 if (setsockopt(global.ipv4.ldp_disc_socket, IPPROTO_IP, IP_MULTICAST_IF,
283 &addr, sizeof(addr)) == -1) {
284 log_warn("%s: error setting IP_MULTICAST_IF, interface %s",
285 __func__, iface->name);
286 return (-1);
287 }
288
289 return (0);
290 }
291
292 int
sock_set_ipv4_mcast_loop(int fd)293 sock_set_ipv4_mcast_loop(int fd)
294 {
295 uint8_t loop = 0;
296
297 if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP,
298 (char *)&loop, sizeof(loop)) == -1) {
299 log_warn("%s: error setting IP_MULTICAST_LOOP", __func__);
300 return (-1);
301 }
302
303 return (0);
304 }
305
306 int
sock_set_ipv6_dscp(int fd,int dscp)307 sock_set_ipv6_dscp(int fd, int dscp)
308 {
309 if (setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &dscp,
310 sizeof(dscp)) == -1) {
311 log_warn("%s: error setting IPV6_TCLASS", __func__);
312 return (-1);
313 }
314
315 return (0);
316 }
317
318 int
sock_set_ipv6_pktinfo(int fd,int enable)319 sock_set_ipv6_pktinfo(int fd, int enable)
320 {
321 if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &enable,
322 sizeof(enable)) == -1) {
323 log_warn("%s: error setting IPV6_RECVPKTINFO", __func__);
324 return (-1);
325 }
326
327 return (0);
328 }
329
330 int
sock_set_ipv6_minhopcount(int fd,int hoplimit)331 sock_set_ipv6_minhopcount(int fd, int hoplimit)
332 {
333 if (setsockopt(fd, IPPROTO_IPV6, IPV6_MINHOPCOUNT,
334 &hoplimit, sizeof(hoplimit)) == -1) {
335 log_warn("%s: error setting IPV6_MINHOPCOUNT", __func__);
336 return (-1);
337 }
338
339 return (0);
340 }
341
342 int
sock_set_ipv6_ucast_hops(int fd,int hoplimit)343 sock_set_ipv6_ucast_hops(int fd, int hoplimit)
344 {
345 if (setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
346 &hoplimit, sizeof(hoplimit)) == -1) {
347 log_warn("%s: error setting IPV6_UNICAST_HOPS", __func__);
348 return (-1);
349 }
350
351 return (0);
352 }
353
354 int
sock_set_ipv6_mcast_hops(int fd,int hoplimit)355 sock_set_ipv6_mcast_hops(int fd, int hoplimit)
356 {
357 if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
358 &hoplimit, sizeof(hoplimit)) == -1) {
359 log_warn("%s: error setting IPV6_MULTICAST_HOPS", __func__);
360 return (-1);
361 }
362
363 return (0);
364 }
365
366 int
sock_set_ipv6_mcast(struct iface * iface)367 sock_set_ipv6_mcast(struct iface *iface)
368 {
369 if (setsockopt(global.ipv6.ldp_disc_socket, IPPROTO_IPV6,
370 IPV6_MULTICAST_IF, &iface->ifindex, sizeof(iface->ifindex)) == -1) {
371 log_warn("%s: error setting IPV6_MULTICAST_IF, interface %s",
372 __func__, iface->name);
373 return (-1);
374 }
375
376 return (0);
377 }
378
379 int
sock_set_ipv6_mcast_loop(int fd)380 sock_set_ipv6_mcast_loop(int fd)
381 {
382 unsigned int loop = 0;
383
384 if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
385 &loop, sizeof(loop)) == -1) {
386 log_warn("%s: error setting IPV6_MULTICAST_LOOP", __func__);
387 return (-1);
388 }
389
390 return (0);
391 }
392