GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/ldpd/socket.c Lines: 0 172 0.0 %
Date: 2017-11-13 Branches: 0 99 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: socket.c,v 1.9 2016/07/01 23:29:55 renato 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
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
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
195
sock_set_reuse(int fd, int enable)
196
{
197
	if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &enable,
198
	    sizeof(int)) < 0) {
199
		log_warn("%s: error setting SO_REUSEADDR", __func__);
200
		return (-1);
201
	}
202
203
	return (0);
204
}
205
206
int
207
sock_set_bindany(int fd, int enable)
208
{
209
	if (setsockopt(fd, SOL_SOCKET, SO_BINDANY, &enable,
210
	    sizeof(int)) < 0) {
211
		log_warn("%s: error setting SO_BINDANY", __func__);
212
		return (-1);
213
	}
214
215
	return (0);
216
}
217
218
int
219
sock_set_ipv4_tos(int fd, int tos)
220
{
221
	if (setsockopt(fd, IPPROTO_IP, IP_TOS, (int *)&tos, sizeof(tos)) < 0) {
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
230
sock_set_ipv4_recvif(int fd, int enable)
231
{
232
	if (setsockopt(fd, IPPROTO_IP, IP_RECVIF, &enable,
233
	    sizeof(enable)) < 0) {
234
		log_warn("%s: error setting IP_RECVIF", __func__);
235
		return (-1);
236
	}
237
	return (0);
238
}
239
240
int
241
sock_set_ipv4_minttl(int fd, int ttl)
242
{
243
	if (setsockopt(fd, IPPROTO_IP, IP_MINTTL, &ttl, sizeof(ttl)) < 0) {
244
		log_warn("%s: error setting IP_MINTTL", __func__);
245
		return (-1);
246
	}
247
248
	return (0);
249
}
250
251
int
252
sock_set_ipv4_ucast_ttl(int fd, int ttl)
253
{
254
	if (setsockopt(fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)) < 0) {
255
		log_warn("%s: error setting IP_TTL", __func__);
256
		return (-1);
257
	}
258
259
	return (0);
260
}
261
262
int
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)) < 0) {
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
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)) < 0) {
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
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)) < 0) {
299
		log_warn("%s: error setting IP_MULTICAST_LOOP", __func__);
300
		return (-1);
301
	}
302
303
	return (0);
304
}
305
306
int
307
sock_set_ipv6_dscp(int fd, int dscp)
308
{
309
	if (setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &dscp,
310
	    sizeof(dscp)) < 0) {
311
		log_warn("%s: error setting IPV6_TCLASS", __func__);
312
		return (-1);
313
	}
314
315
	return (0);
316
}
317
318
int
319
sock_set_ipv6_pktinfo(int fd, int enable)
320
{
321
	if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &enable,
322
	    sizeof(enable)) < 0) {
323
		log_warn("%s: error setting IPV6_RECVPKTINFO", __func__);
324
		return (-1);
325
	}
326
327
	return (0);
328
}
329
330
int
331
sock_set_ipv6_minhopcount(int fd, int hoplimit)
332
{
333
	if (setsockopt(fd, IPPROTO_IPV6, IPV6_MINHOPCOUNT,
334
	    &hoplimit, sizeof(hoplimit)) < 0) {
335
		log_warn("%s: error setting IPV6_MINHOPCOUNT", __func__);
336
		return (-1);
337
	}
338
339
	return (0);
340
}
341
342
int
343
sock_set_ipv6_ucast_hops(int fd, int hoplimit)
344
{
345
	if (setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
346
	    &hoplimit, sizeof(hoplimit)) < 0) {
347
		log_warn("%s: error setting IPV6_UNICAST_HOPS", __func__);
348
		return (-1);
349
	}
350
351
	return (0);
352
}
353
354
int
355
sock_set_ipv6_mcast_hops(int fd, int hoplimit)
356
{
357
	if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
358
	    &hoplimit, sizeof(hoplimit)) < 0) {
359
		log_warn("%s: error setting IPV6_MULTICAST_HOPS", __func__);
360
		return (-1);
361
	}
362
363
	return (0);
364
}
365
366
int
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)) < 0) {
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
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)) < 0) {
386
		log_warn("%s: error setting IPV6_MULTICAST_LOOP", __func__);
387
		return (-1);
388
	}
389
390
	return (0);
391
}