X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/6023a6ad2ac0294879b14127f62795095da573b5..38965d80d70cacd0c944d32f7107549a3a272b35:/src/src/routers/iplookup.c diff --git a/src/src/routers/iplookup.c b/src/src/routers/iplookup.c index 33329f887..b88212e5c 100644 --- a/src/src/routers/iplookup.c +++ b/src/src/routers/iplookup.c @@ -2,11 +2,15 @@ * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2009 */ +/* Copyright (c) The Exim Maintainers 2020 - 2023 */ +/* Copyright (c) University of Cambridge 1995 - 2018 */ /* See the file NOTICE for conditions of use and distribution. */ +/* SPDX-License-Identifier: GPL-2.0-or-later */ #include "../exim.h" + +#ifdef ROUTER_IPLOOKUP /* Remainder of file */ #include "rf_functions.h" #include "iplookup.h" @@ -21,21 +25,21 @@ optionlist iplookup_router_options[] = { { "hosts", opt_stringptr, - (void *)(offsetof(iplookup_router_options_block, hosts)) }, + OPT_OFF(iplookup_router_options_block, hosts) }, { "optional", opt_bool, - (void *)(offsetof(iplookup_router_options_block, optional)) }, + OPT_OFF(iplookup_router_options_block, optional) }, { "port", opt_int, - (void *)(offsetof(iplookup_router_options_block, port)) }, + OPT_OFF(iplookup_router_options_block, port) }, { "protocol", opt_stringptr, - (void *)(offsetof(iplookup_router_options_block, protocol_name)) }, + OPT_OFF(iplookup_router_options_block, protocol_name) }, { "query", opt_stringptr, - (void *)(offsetof(iplookup_router_options_block, query)) }, + OPT_OFF(iplookup_router_options_block, query) }, { "reroute", opt_stringptr, - (void *)(offsetof(iplookup_router_options_block, reroute)) }, + OPT_OFF(iplookup_router_options_block, reroute) }, { "response_pattern", opt_stringptr, - (void *)(offsetof(iplookup_router_options_block, response_pattern)) }, + OPT_OFF(iplookup_router_options_block, response_pattern) }, { "timeout", opt_time, - (void *)(offsetof(iplookup_router_options_block, timeout)) } + OPT_OFF(iplookup_router_options_block, timeout) } }; /* Size of the options list. An extern variable has to be used so that its @@ -44,6 +48,20 @@ address can appear in the tables drtables.c. */ int iplookup_router_options_count = sizeof(iplookup_router_options)/sizeof(optionlist); + +#ifdef MACRO_PREDEF + +/* Dummy entries */ +iplookup_router_options_block iplookup_router_option_defaults = {0}; +void iplookup_router_init(router_instance *rblock) {} +int iplookup_router_entry(router_instance *rblock, address_item *addr, + struct passwd *pw, int verify, address_item **addr_local, + address_item **addr_remote, address_item **addr_new, + address_item **addr_succeed) {return 0;} + +#else /*!MACRO_PREDEF*/ + + /* Default private options block for the iplookup router. */ iplookup_router_options_block iplookup_router_option_defaults = { @@ -69,10 +87,10 @@ iplookup_router_options_block iplookup_router_option_defaults = { consistency checks to be done, or anything else that needs to be set up. */ void -iplookup_router_init(router_instance *rblock) +iplookup_router_init(router_instance * rblock) { -iplookup_router_options_block *ob = - (iplookup_router_options_block *)(rblock->options_block); +iplookup_router_options_block * ob = + (iplookup_router_options_block *) rblock->options_block; /* A port and a host list must be given */ @@ -80,13 +98,13 @@ if (ob->port < 0) log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s router:\n " "a port must be specified", rblock->name); -if (ob->hosts == NULL) +if (!ob->hosts) log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s router:\n " "a host list must be specified", rblock->name); /* Translate protocol name into value */ -if (ob->protocol_name != NULL) +if (ob->protocol_name) { if (Ustrcmp(ob->protocol_name, "udp") == 0) ob->protocol = ip_udp; else if (Ustrcmp(ob->protocol_name, "tcp") == 0) ob->protocol = ip_tcp; @@ -96,9 +114,9 @@ if (ob->protocol_name != NULL) /* If a response pattern is given, compile it now to get the error early. */ -if (ob->response_pattern != NULL) +if (ob->response_pattern) ob->re_response_pattern = - regex_must_compile(ob->response_pattern, FALSE, TRUE); + regex_must_compile(ob->response_pattern, MCS_NOFLAGS, TRUE); } @@ -146,40 +164,33 @@ uschar *reply; uschar *hostname, *reroute, *domain; const uschar *listptr; uschar host_buffer[256]; -host_item *host = store_get(sizeof(host_item)); +host_item *host = store_get(sizeof(host_item), GET_UNTAINTED); address_item *new_addr; iplookup_router_options_block *ob = (iplookup_router_options_block *)(rblock->options_block); -const pcre *re = ob->re_response_pattern; +const pcre2_code *re = ob->re_response_pattern; int count, query_len, rc; int sep = 0; -addr_local = addr_local; /* Keep picky compilers happy */ -addr_remote = addr_remote; -addr_succeed = addr_succeed; -pw = pw; - DEBUG(D_route) debug_printf("%s router called for %s: domain = %s\n", rblock->name, addr->address, addr->domain); -reply = store_get(256); +reply = store_get(256, GET_TAINTED); /* Build the query string to send. If not explicitly given, a default of "user@domain user@domain" is used. */ -if (ob->query == NULL) +GET_OPTION("query"); +if (!ob->query) query = string_sprintf("%s@%s %s@%s", addr->local_part, addr->domain, addr->local_part, addr->domain); else - { - query = expand_string(ob->query); - if (query == NULL) + if (!(query = expand_string(ob->query))) { addr->message = string_sprintf("%s router: failed to expand %s: %s", rblock->name, ob->query, expand_string_message); return DEFER; } - } query_len = Ustrlen(query); DEBUG(D_route) debug_printf("%s router query is \"%s\"\n", rblock->name, @@ -190,8 +201,9 @@ response it received. Initialization insists on the port being set and there being a host list. */ listptr = ob->hosts; +/* not expanded so should never be tainted */ while ((hostname = string_nextinlist(&listptr, &sep, host_buffer, - sizeof(host_buffer))) != NULL) + sizeof(host_buffer)))) { host_item *h; @@ -207,27 +219,30 @@ while ((hostname = string_nextinlist(&listptr, &sep, host_buffer, host->address = host->name; else { +/*XXX might want dnssec request/require on an iplookup router? */ int rc = host_find_byname(host, NULL, HOST_FIND_QUALIFY_SINGLE, NULL, TRUE); if (rc == HOST_FIND_FAILED || rc == HOST_FIND_AGAIN) continue; } /* Loop for possible multiple IP addresses for the given name. */ - for (h = host; h != NULL; h = h->next) + for (h = host; h; h = h->next) { - int host_af, query_socket; + int host_af; + client_conn_ctx query_cctx = {0}; /* Skip any hosts for which we have no address */ - if (h->address == NULL) continue; + if (!h->address) continue; /* Create a socket, for UDP or TCP, as configured. IPv6 addresses are detected by checking for a colon in the address. */ host_af = (Ustrchr(h->address, ':') != NULL)? AF_INET6 : AF_INET; - query_socket = ip_socket((ob->protocol == ip_udp)? SOCK_DGRAM:SOCK_STREAM, + + query_cctx.sock = ip_socket(ob->protocol == ip_udp ? SOCK_DGRAM:SOCK_STREAM, host_af); - if (query_socket < 0) + if (query_cctx.sock < 0) { if (ob->optional) return PASS; addr->message = string_sprintf("failed to create socket in %s router", @@ -238,10 +253,12 @@ while ((hostname = string_nextinlist(&listptr, &sep, host_buffer, /* Connect to the remote host, under a timeout. In fact, timeouts can occur here only for TCP calls; for a UDP socket, "connect" always works (the router will timeout later on the read call). */ +/*XXX could take advantage of TFO */ - if (ip_connect(query_socket, host_af, h->address,ob->port, ob->timeout) < 0) + if (ip_connect(query_cctx.sock, host_af, h->address,ob->port, ob->timeout, + ob->protocol == ip_udp ? NULL : &tcp_fastopen_nodata) < 0) { - close(query_socket); + close(query_cctx.sock); DEBUG(D_route) debug_printf("connection to %s failed: %s\n", h->address, strerror(errno)); @@ -250,18 +267,18 @@ while ((hostname = string_nextinlist(&listptr, &sep, host_buffer, /* Send the query. If it fails, just continue with the next address. */ - if (send(query_socket, query, query_len, 0) < 0) + if (send(query_cctx.sock, query, query_len, 0) < 0) { DEBUG(D_route) debug_printf("send to %s failed\n", h->address); - (void)close(query_socket); + (void)close(query_cctx.sock); continue; } /* Read the response and close the socket. If the read fails, try the next IP address. */ - count = ip_recv(query_socket, reply, sizeof(reply) - 1, ob->timeout); - (void)close(query_socket); + count = ip_recv(&query_cctx, reply, sizeof(reply) - 1, time(NULL) + ob->timeout); + (void)close(query_cctx.sock); if (count <= 0) { DEBUG(D_route) debug_printf("%s from %s\n", (errno == ETIMEDOUT)? @@ -281,7 +298,7 @@ while ((hostname = string_nextinlist(&listptr, &sep, host_buffer, /* If h == NULL we have tried all the IP addresses and failed on all of them, so we must continue to try more host names. Otherwise we have succeeded. */ - if (h != NULL) break; + if (h) break; } @@ -345,23 +362,24 @@ else /* If an explicit rerouting string is specified, expand it. Otherwise, use what was sent back verbatim. */ -if (ob->reroute != NULL) +GET_OPTION("reroute"); +if (ob->reroute) { reroute = expand_string(ob->reroute); expand_nmax = -1; - if (reroute == NULL) + if (!reroute) { addr->message = string_sprintf("%s router: failed to expand %s: %s", rblock->name, ob->reroute, expand_string_message); return DEFER; } } -else reroute = reply; +else + reroute = reply; /* We should now have a new address in the form user@domain. */ -domain = Ustrchr(reroute, '@'); -if (domain == NULL) +if (!(domain = Ustrchr(reroute, '@'))) { log_write(0, LOG_MAIN, "%s router: reroute string %s is not of the form " "user@domain", rblock->name, reroute); @@ -376,17 +394,16 @@ the chain of new addressess. */ new_addr = deliver_make_addr(reroute, TRUE); new_addr->parent = addr; -copyflag(new_addr, addr, af_propagate); new_addr->prop = addr->prop; -if (addr->child_count == SHRT_MAX) +if (addr->child_count == USHRT_MAX) log_write(0, LOG_MAIN|LOG_PANIC_DIE, "%s router generated more than %d " - "child addresses for <%s>", rblock->name, SHRT_MAX, addr->address); + "child addresses for <%s>", rblock->name, USHRT_MAX, addr->address); addr->child_count++; new_addr->next = *addr_new; *addr_new = new_addr; -/* Set up the errors address, if any, and the additional and removeable headers +/* Set up the errors address, if any, and the additional and removable headers for this new address. */ rc = rf_get_errors_address(addr, rblock, verify, &new_addr->prop.errors_address); @@ -399,4 +416,6 @@ if (rc != OK) return rc; return OK; } +#endif /*!MACRO_PREDEF*/ +#endif /*ROUTER_IPLOOKUP*/ /* End of routers/iplookup.c */