1 /* $OpenBSD: relay_udp.c,v 1.47 2017/07/04 19:59:51 benno Exp $ */ 2 3 /* 4 * Copyright (c) 2007 - 2013 Reyk Floeter <reyk@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 #include <sys/queue.h> 21 #include <sys/time.h> 22 #include <sys/socket.h> 23 #include <sys/tree.h> 24 25 #include <netinet/in.h> 26 #include <arpa/inet.h> 27 28 #include <signal.h> 29 #include <errno.h> 30 #include <fcntl.h> 31 #include <stdlib.h> 32 #include <string.h> 33 #include <unistd.h> 34 #include <stdio.h> 35 #include <event.h> 36 #include <imsg.h> 37 38 #include "relayd.h" 39 40 extern volatile sig_atomic_t relay_sessions; 41 extern objid_t relay_conid; 42 43 static struct relayd *env = NULL; 44 struct shuffle relay_shuffle; 45 46 int relay_udp_socket(struct sockaddr_storage *, in_port_t, 47 struct protocol *); 48 void relay_udp_request(struct rsession *); 49 void relay_udp_timeout(int, short, void *); 50 51 void relay_dns_log(struct rsession *, u_int8_t *, size_t); 52 void *relay_dns_validate(struct rsession *, 53 struct relay *, struct sockaddr_storage *, 54 u_int8_t *, size_t); 55 int relay_dns_request(struct rsession *); 56 void relay_udp_response(int, short, void *); 57 void relay_dns_result(struct rsession *, u_int8_t *, size_t); 58 int relay_dns_cmp(struct rsession *, struct rsession *); 59 60 void 61 relay_udp_privinit(struct relay *rlay) 62 { 63 if (rlay->rl_conf.flags & F_TLS) 64 fatalx("tls over udp is not supported"); 65 rlay->rl_conf.flags |= F_UDP; 66 } 67 68 void 69 relay_udp_init(struct relayd *x_env, struct relay *rlay) 70 { 71 struct protocol *proto = rlay->rl_proto; 72 73 if (env == NULL) 74 env = x_env; 75 76 switch (proto->type) { 77 case RELAY_PROTO_DNS: 78 proto->validate = relay_dns_validate; 79 proto->request = relay_dns_request; 80 proto->cmp = relay_dns_cmp; 81 shuffle_init(&relay_shuffle); 82 break; 83 default: 84 fatalx("unsupported udp protocol"); 85 break; 86 } 87 } 88 89 int 90 relay_udp_bind(struct sockaddr_storage *ss, in_port_t port, 91 struct protocol *proto) 92 { 93 int s; 94 95 if ((s = relay_udp_socket(ss, port, proto)) == -1) 96 return (-1); 97 98 if (bind(s, (struct sockaddr *)ss, ss->ss_len) == -1) 99 goto bad; 100 101 return (s); 102 103 bad: 104 close(s); 105 return (-1); 106 } 107 108 int 109 relay_udp_socket(struct sockaddr_storage *ss, in_port_t port, 110 struct protocol *proto) 111 { 112 int s = -1, val; 113 114 if (relay_socket_af(ss, port) == -1) 115 goto bad; 116 117 if ((s = socket(ss->ss_family, SOCK_DGRAM | SOCK_NONBLOCK, 118 IPPROTO_UDP)) == -1) 119 goto bad; 120 121 /* 122 * Socket options 123 */ 124 if (proto->tcpflags & TCPFLAG_BUFSIZ) { 125 val = proto->tcpbufsiz; 126 if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, 127 &val, sizeof(val)) == -1) 128 goto bad; 129 val = proto->tcpbufsiz; 130 if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, 131 &val, sizeof(val)) == -1) 132 goto bad; 133 } 134 135 /* 136 * IP options 137 */ 138 if (proto->tcpflags & TCPFLAG_IPTTL) { 139 val = (int)proto->tcpipttl; 140 switch (ss->ss_family) { 141 case AF_INET: 142 if (setsockopt(s, IPPROTO_IP, IP_TTL, 143 &val, sizeof(val)) == -1) 144 goto bad; 145 break; 146 case AF_INET6: 147 if (setsockopt(s, IPPROTO_IPV6, IPV6_UNICAST_HOPS, 148 &val, sizeof(val)) == -1) 149 goto bad; 150 break; 151 } 152 } 153 if (proto->tcpflags & TCPFLAG_IPMINTTL) { 154 val = (int)proto->tcpipminttl; 155 switch (ss->ss_family) { 156 case AF_INET: 157 if (setsockopt(s, IPPROTO_IP, IP_MINTTL, 158 &val, sizeof(val)) == -1) 159 goto bad; 160 break; 161 case AF_INET6: 162 if (setsockopt(s, IPPROTO_IPV6, IPV6_MINHOPCOUNT, 163 &val, sizeof(val)) == -1) 164 goto bad; 165 break; 166 } 167 } 168 169 return (s); 170 171 bad: 172 if (s != -1) 173 close(s); 174 return (-1); 175 } 176 177 void 178 relay_udp_response(int fd, short sig, void *arg) 179 { 180 struct rsession *con = arg; 181 struct relay *rlay = con->se_relay; 182 struct protocol *proto = rlay->rl_proto; 183 void *priv = NULL; 184 struct sockaddr_storage ss; 185 u_int8_t buf[IBUF_READ_SIZE]; 186 ssize_t len; 187 socklen_t slen; 188 189 if (sig == EV_TIMEOUT) { 190 relay_udp_timeout(fd, sig, arg); 191 return; 192 } 193 194 if (relay_sessions >= RELAY_MAX_SESSIONS || 195 rlay->rl_conf.flags & F_DISABLE) 196 return; 197 198 slen = sizeof(ss); 199 if ((len = recvfrom(fd, buf, sizeof(buf), 0, 200 (struct sockaddr*)&ss, &slen)) < 1) 201 return; 202 203 /* Parse and validate the packet header */ 204 if (proto->validate != NULL && 205 (priv = (*proto->validate)(con, rlay, &ss, buf, len)) == NULL) 206 return; 207 208 relay_close(con, "unknown response"); 209 free(priv); 210 } 211 212 void 213 relay_udp_server(int fd, short sig, void *arg) 214 { 215 struct privsep *ps = env->sc_ps; 216 struct relay *rlay = arg; 217 struct protocol *proto = rlay->rl_proto; 218 struct rsession *con = NULL; 219 struct ctl_natlook *cnl = NULL; 220 socklen_t slen; 221 struct timeval tv; 222 struct sockaddr_storage ss; 223 u_int8_t buf[IBUF_READ_SIZE]; 224 void *priv = NULL; 225 ssize_t len; 226 227 event_add(&rlay->rl_ev, NULL); 228 229 if (relay_sessions >= RELAY_MAX_SESSIONS || 230 rlay->rl_conf.flags & F_DISABLE) 231 return; 232 233 slen = sizeof(ss); 234 if ((len = recvfrom(fd, buf, sizeof(buf), 0, 235 (struct sockaddr*)&ss, &slen)) < 1) 236 return; 237 238 if (proto->validate != NULL && 239 (priv = (*proto->validate)(NULL, rlay, &ss, buf, len)) == NULL) 240 return; 241 242 if ((con = calloc(1, sizeof(*con))) == NULL) { 243 free(priv); 244 return; 245 } 246 247 /* 248 * Replace the DNS request Id with a random Id. 249 */ 250 con->se_priv = priv; 251 con->se_in.s = -1; 252 con->se_out.s = -1; 253 con->se_in.dst = &con->se_out; 254 con->se_out.dst = &con->se_in; 255 con->se_in.con = con; 256 con->se_out.con = con; 257 con->se_relay = rlay; 258 con->se_id = ++relay_conid; 259 con->se_in.dir = RELAY_DIR_REQUEST; 260 con->se_out.dir = RELAY_DIR_RESPONSE; 261 con->se_retry = rlay->rl_conf.dstretry; 262 con->se_out.port = rlay->rl_conf.dstport; 263 switch (ss.ss_family) { 264 case AF_INET: 265 con->se_in.port = ((struct sockaddr_in *)&ss)->sin_port; 266 break; 267 case AF_INET6: 268 con->se_in.port = ((struct sockaddr_in6 *)&ss)->sin6_port; 269 break; 270 } 271 bcopy(&ss, &con->se_in.ss, sizeof(con->se_in.ss)); 272 273 getmonotime(&con->se_tv_start); 274 bcopy(&con->se_tv_start, &con->se_tv_last, sizeof(con->se_tv_last)); 275 276 relay_sessions++; 277 SPLAY_INSERT(session_tree, &rlay->rl_sessions, con); 278 relay_session_publish(con); 279 280 /* Increment the per-relay session counter */ 281 rlay->rl_stats[ps->ps_instance].last++; 282 283 /* Pre-allocate output buffer */ 284 con->se_out.output = evbuffer_new(); 285 if (con->se_out.output == NULL) { 286 relay_close(con, "failed to allocate output buffer"); 287 return; 288 } 289 290 /* Pre-allocate log buffer */ 291 con->se_haslog = 0; 292 con->se_log = evbuffer_new(); 293 if (con->se_log == NULL) { 294 relay_close(con, "failed to allocate log buffer"); 295 return; 296 } 297 298 if (rlay->rl_conf.flags & F_NATLOOK) { 299 if ((cnl = calloc(1, sizeof(*cnl))) == NULL) { 300 relay_close(con, "failed to allocate natlookup"); 301 return; 302 } 303 } 304 305 /* Save the received data */ 306 if (evbuffer_add(con->se_out.output, buf, len) == -1) { 307 relay_close(con, "failed to store buffer"); 308 free(cnl); 309 return; 310 } 311 312 if (cnl != NULL) { 313 con->se_cnl = cnl; 314 bzero(cnl, sizeof(*cnl)); 315 cnl->in = -1; 316 cnl->id = con->se_id; 317 cnl->proc = ps->ps_instance; 318 cnl->proto = IPPROTO_UDP; 319 bcopy(&con->se_in.ss, &cnl->src, sizeof(cnl->src)); 320 bcopy(&rlay->rl_conf.ss, &cnl->dst, sizeof(cnl->dst)); 321 proc_compose(env->sc_ps, PROC_PFE, 322 IMSG_NATLOOK, cnl, sizeof(*cnl)); 323 324 /* Schedule timeout */ 325 evtimer_set(&con->se_ev, relay_natlook, con); 326 bcopy(&rlay->rl_conf.timeout, &tv, sizeof(tv)); 327 evtimer_add(&con->se_ev, &tv); 328 return; 329 } 330 331 relay_session(con); 332 } 333 334 void 335 relay_udp_timeout(int fd, short sig, void *arg) 336 { 337 struct rsession *con = arg; 338 339 if (sig != EV_TIMEOUT) 340 fatalx("invalid timeout event"); 341 342 relay_close(con, "udp timeout"); 343 } 344 345 /* 346 * Domain Name System support 347 */ 348 349 struct relay_dns_priv { 350 u_int16_t dp_inkey; 351 u_int16_t dp_outkey; 352 }; 353 354 struct relay_dnshdr { 355 u_int16_t dns_id; 356 357 u_int8_t dns_flags0; 358 #define DNS_F0_QR 0x80 /* response flag */ 359 #define DNS_F0_OPCODE 0x78 /* message type */ 360 #define DNS_F0_AA 0x04 /* authorative answer */ 361 #define DNS_F0_TC 0x02 /* truncated message */ 362 #define DNS_F0_RD 0x01 /* recursion desired */ 363 364 u_int8_t dns_flags1; 365 #define DNS_F1_RA 0x80 /* recursion available */ 366 #define DNS_F1_RES 0x40 /* reserved */ 367 #define DNS_F1_AD 0x20 /* authentic data */ 368 #define DNS_F1_CD 0x10 /* checking disabled */ 369 #define DNS_F1_RCODE 0x0f /* response code */ 370 371 u_int16_t dns_qdcount; 372 u_int16_t dns_ancount; 373 u_int16_t dns_nscount; 374 u_int16_t dns_arcount; 375 } __packed; 376 377 void 378 relay_dns_log(struct rsession *con, u_int8_t *buf, size_t len) 379 { 380 struct relay_dnshdr *hdr = (struct relay_dnshdr *)buf; 381 382 /* Validate the header length */ 383 if (len < sizeof(*hdr)) { 384 log_debug("%s: session %d: short dns packet", __func__, 385 con->se_id); 386 return; 387 } 388 389 log_debug("%s: session %d: %s id 0x%x " 390 "flags 0x%x:0x%x qd %u an %u ns %u ar %u", __func__, 391 con->se_id, 392 hdr->dns_flags0 & DNS_F0_QR ? "response" : "request", 393 ntohs(hdr->dns_id), 394 hdr->dns_flags0, 395 hdr->dns_flags1, 396 ntohs(hdr->dns_qdcount), 397 ntohs(hdr->dns_ancount), 398 ntohs(hdr->dns_nscount), 399 ntohs(hdr->dns_arcount)); 400 } 401 402 void * 403 relay_dns_validate(struct rsession *con, struct relay *rlay, 404 struct sockaddr_storage *ss, u_int8_t *buf, size_t len) 405 { 406 struct relay_dnshdr *hdr = (struct relay_dnshdr *)buf; 407 struct rsession lookup; 408 u_int16_t key; 409 struct relay_dns_priv *priv, lpriv; 410 411 /* Validate the header length */ 412 if (len < sizeof(*hdr)) 413 return (NULL); 414 415 key = ntohs(hdr->dns_id); 416 417 /* 418 * Check if the header has the response flag set, otherwise 419 * return 0 to tell the UDP server to create a new session. 420 */ 421 if ((hdr->dns_flags0 & DNS_F0_QR) == 0) { 422 priv = malloc(sizeof(struct relay_dns_priv)); 423 if (priv == NULL) 424 return (NULL); 425 priv->dp_inkey = shuffle_generate16(&relay_shuffle); 426 priv->dp_outkey = key; 427 return ((void *)priv); 428 } 429 430 /* 431 * Lookup if this response is for a known session and if the 432 * remote host matches the original destination of the request. 433 */ 434 if (con == NULL) { 435 lpriv.dp_inkey = key; 436 lookup.se_priv = &lpriv; 437 if ((con = SPLAY_FIND(session_tree, 438 &rlay->rl_sessions, &lookup)) != NULL && 439 con->se_priv != NULL && 440 relay_cmp_af(ss, &con->se_out.ss) == 0) 441 relay_dns_result(con, buf, len); 442 } else { 443 priv = con->se_priv; 444 if (priv == NULL || key != priv->dp_inkey) { 445 relay_close(con, "invalid response"); 446 return (NULL); 447 } 448 relay_dns_result(con, buf, len); 449 } 450 451 /* 452 * This is not a new session, ignore it in the UDP server. 453 */ 454 return (NULL); 455 } 456 457 int 458 relay_dns_request(struct rsession *con) 459 { 460 struct relay *rlay = con->se_relay; 461 struct relay_dns_priv *priv = con->se_priv; 462 u_int8_t *buf = EVBUFFER_DATA(con->se_out.output); 463 size_t len = EVBUFFER_LENGTH(con->se_out.output); 464 struct relay_dnshdr *hdr; 465 socklen_t slen; 466 467 if (buf == NULL || priv == NULL || len < 1) 468 return (-1); 469 if (log_getverbose() > 1) 470 relay_dns_log(con, buf, len); 471 472 getmonotime(&con->se_tv_start); 473 474 if (!TAILQ_EMPTY(&rlay->rl_tables)) { 475 if (relay_from_table(con) != 0) 476 return (-1); 477 } else if (con->se_out.ss.ss_family == AF_UNSPEC) { 478 bcopy(&rlay->rl_conf.dstss, &con->se_out.ss, 479 sizeof(con->se_out.ss)); 480 con->se_out.port = rlay->rl_conf.dstport; 481 } 482 483 if ((con->se_out.s = relay_udp_socket(&con->se_out.ss, 484 con->se_out.port, rlay->rl_proto)) == -1) 485 return (-1); 486 slen = con->se_out.ss.ss_len; 487 488 hdr = (struct relay_dnshdr *)buf; 489 hdr->dns_id = htons(priv->dp_inkey); 490 491 retry: 492 if (sendto(con->se_out.s, buf, len, 0, 493 (struct sockaddr *)&con->se_out.ss, slen) == -1) { 494 if (con->se_retry) { 495 con->se_retry--; 496 log_debug("%s: session %d: " 497 "forward failed: %s, %s", __func__, 498 con->se_id, strerror(errno), 499 con->se_retry ? "next retry" : "last retry"); 500 goto retry; 501 } 502 log_debug("%s: session %d: forward failed: %s", __func__, 503 con->se_id, strerror(errno)); 504 return (-1); 505 } 506 507 event_again(&con->se_ev, con->se_out.s, EV_TIMEOUT|EV_READ, 508 relay_udp_response, &con->se_tv_start, &rlay->rl_conf.timeout, con); 509 510 return (0); 511 } 512 513 void 514 relay_dns_result(struct rsession *con, u_int8_t *buf, size_t len) 515 { 516 struct relay *rlay = con->se_relay; 517 struct relay_dns_priv *priv = con->se_priv; 518 struct relay_dnshdr *hdr; 519 socklen_t slen; 520 521 if (priv == NULL) 522 fatalx("%s: response to invalid session", __func__); 523 524 if (log_getverbose() > 1) 525 relay_dns_log(con, buf, len); 526 527 /* 528 * Replace the random DNS request Id with the original Id 529 */ 530 hdr = (struct relay_dnshdr *)buf; 531 hdr->dns_id = htons(priv->dp_outkey); 532 533 slen = con->se_out.ss.ss_len; 534 if (sendto(rlay->rl_s, buf, len, 0, 535 (struct sockaddr *)&con->se_in.ss, slen) == -1) { 536 relay_close(con, "response failed"); 537 return; 538 } 539 540 relay_close(con, "session closed"); 541 } 542 543 int 544 relay_dns_cmp(struct rsession *a, struct rsession *b) 545 { 546 struct relay_dns_priv *ap = a->se_priv; 547 struct relay_dns_priv *bp = b->se_priv; 548 549 if (ap == NULL || bp == NULL) 550 fatalx("%s: invalid session", __func__); 551 552 return (memcmp(&ap->dp_inkey, &bp->dp_inkey, sizeof(u_int16_t))); 553 } 554