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 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)) == -1) { 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)) == -1) { 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)) == -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 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 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 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 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 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 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 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 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 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 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 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 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 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